refactor(scan): remove yum-security related code (#836)

* refactor(scan): remove yum-security related code

* fix(reporting): error if no OVAL entry
This commit is contained in:
Kota Kanbe
2019-06-14 11:42:38 +09:00
committed by GitHub
parent 3634afdb81
commit eb9f9680ec
10 changed files with 13 additions and 1999 deletions

View File

@@ -114,12 +114,7 @@ Vuls uses multiple vulnerability databases
[Deep Scan](https://vuls.io/docs/en/architecture-deep-scan.html)
- Scan with root privilege
- Parses the Changelog
Changelog has a history of version changes. When a security issue is fixed, the relevant CVE ID is listed.
By parsing the changelog and analysing the updates between the installed version of software on the server and the newest version of that software
it's possible to create a list of all vulnerabilities that need to be fixed.
- Sometimes load on the scan target server
- Same as fast root scan for now
### [Remote scan, Local scan mode, Server mode](https://vuls.io/docs/en/architecture-remote-local.html)

2
go.sum
View File

@@ -264,6 +264,8 @@ github.com/kotakanbe/goval-dictionary v0.1.3-0.20190612145907-3fbb67115698 h1:5/
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190612145907-3fbb67115698/go.mod h1:D0FzzGCYCJCgPy5+wGgEOvWTb8fxUxqdxkWM2JDwguA=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613041505-2362c088a437 h1:gnwqfC+G78bmvVHETLvZOUKopUD/ljQAdwcvHiLKMKA=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613041505-2362c088a437/go.mod h1:VupP39J8370MdBkmvQQVmuYf98VrcQzhiGo+UiNW4rs=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613053258-078b163b76ec h1:gMji7JMOrnUYUorYUTM7TRlvy8D613WkQhayEQhBsFI=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613053258-078b163b76ec/go.mod h1:VupP39J8370MdBkmvQQVmuYf98VrcQzhiGo+UiNW4rs=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613053258-8b98657de17d h1:S2hGRg/3mxi8eR7DROKT9kqTEjGLgm4dDHm72/DIJrQ=
github.com/kotakanbe/goval-dictionary v0.1.3-0.20190613053258-8b98657de17d/go.mod h1:VupP39J8370MdBkmvQQVmuYf98VrcQzhiGo+UiNW4rs=
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96 h1:xNVK0mQJdQjw+QYeaMM4G6fvucWr8rTGGIhlPakx1wU=

View File

@@ -119,7 +119,6 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int)
if v.LastModified.After(ovalContent.LastModified) {
util.Log.Debugf("%s, OvalID: %d ignroed: ",
cve.CveID, defPacks.def.ID)
continue
} else {
util.Log.Debugf("%s OVAL will be overwritten", cve.CveID)
}

View File

@@ -67,7 +67,6 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
}
cpeURIs := []string{}
// runningContainer
if len(r.Container.ContainerID) == 0 {
cpeURIs = c.Conf.Servers[r.ServerName].CpeNames
owaspDCXMLPath := c.Conf.Servers[r.ServerName].OwaspDCXMLPath
@@ -80,6 +79,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
cpeURIs = append(cpeURIs, cpes...)
}
} else {
// runningContainer
if s, ok := c.Conf.Servers[r.ServerName]; ok {
if con, ok := s.Containers[r.Container.Name]; ok {
cpeURIs = con.Cpes
@@ -325,8 +325,7 @@ func FillWithOval(driver ovaldb.DB, r *models.ScanResult) (nCVEs int, err error)
return 0, err
}
if !ok {
util.Log.Warnf("OVAL entries of %s %s are not found. It's recommended to use OVAL to improve scanning accuracy. For details, see https://github.com/kotakanbe/goval-dictionary#usage , Then report with --ovaldb-path or --ovaldb-url flag", ovalFamily, r.Release)
return 0, nil
return 0, xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see https://github.com/kotakanbe/goval-dictionary#usage", ovalFamily, r.Release)
}
_, err = ovalClient.CheckIfOvalFresh(driver, ovalFamily, r.Release)

View File

@@ -100,18 +100,6 @@ func (o rootPrivAmazon) repoquery() bool {
return false
}
func (o rootPrivAmazon) yumRepolist() bool {
return false
}
func (o rootPrivAmazon) yumUpdateInfo() bool {
return false
}
func (o rootPrivAmazon) yumChangelog() bool {
return false
}
func (o rootPrivAmazon) yumMakeCache() bool {
return false
}

View File

@@ -59,11 +59,7 @@ func (o *centos) depsFastRoot() []string {
}
func (o *centos) depsDeep() []string {
return []string{
"yum-utils",
"yum-plugin-ps",
"yum-plugin-changelog",
}
return o.depsFastRoot()
}
func (o *centos) checkIfSudoNoPasswd() error {
@@ -107,18 +103,6 @@ func (o rootPrivCentos) repoquery() bool {
return false
}
func (o rootPrivCentos) yumRepolist() bool {
return false
}
func (o rootPrivCentos) yumUpdateInfo() bool {
return false
}
func (o rootPrivCentos) yumChangelog() bool {
return false
}
func (o rootPrivCentos) yumMakeCache() bool {
return false
}

View File

@@ -52,59 +52,11 @@ func (o *oracle) depsFast() []string {
}
func (o *oracle) depsFastRoot() []string {
if o.getServerInfo().Mode.IsOffline() {
//TODO
// return []string{"yum-plugin-ps"}
}
majorVersion, _ := o.Distro.MajorVersion()
switch majorVersion {
case 5:
return []string{
"yum-utils",
"yum-security",
}
case 6:
return []string{
"yum-utils",
"yum-plugin-security",
//TODO
// return []string{"yum-plugin-ps"}
}
default:
return []string{
"yum-utils",
//TODO
// return []string{"yum-plugin-ps"}
}
}
return []string{"yum-utils"}
}
func (o *oracle) depsDeep() []string {
majorVersion, _ := o.Distro.MajorVersion()
switch majorVersion {
case 5:
return []string{
"yum-utils",
"yum-security",
"yum-changelog",
}
case 6:
return []string{
"yum-utils",
"yum-plugin-security",
"yum-plugin-changelog",
//TODO
// return []string{"yum-plugin-ps"}
}
default:
return []string{
"yum-utils",
"yum-plugin-changelog",
//TODO
// return []string{"yum-plugin-ps"}
}
}
return o.depsFastRoot()
}
func (o *oracle) checkIfSudoNoPasswd() error {
@@ -126,21 +78,7 @@ func (o *oracle) sudoNoPasswdCmdsFastRoot() []cmd {
if o.getServerInfo().Mode.IsOffline() {
return cmds
}
majorVersion, _ := o.Distro.MajorVersion()
if majorVersion < 6 {
return []cmd{
{"yum repolist --color=never", exitStatusZero},
{"yum list-security --security --color=never", exitStatusZero},
{"yum info-security --color=never", exitStatusZero},
{"repoquery -h", exitStatusZero},
}
}
return append(cmds,
cmd{"yum repolist --color=never", exitStatusZero},
cmd{"yum updateinfo list updates --security --color=never", exitStatusZero},
cmd{"yum updateinfo updates --security --color=never", exitStatusZero},
cmd{"repoquery -h", exitStatusZero})
return append(cmds, cmd{"repoquery -h", exitStatusZero})
}
func (o *oracle) sudoNoPasswdCmdsDeep() []cmd {
@@ -153,19 +91,6 @@ func (o rootPrivOracle) repoquery() bool {
return true
}
func (o rootPrivOracle) yumRepolist() bool {
return true
}
func (o rootPrivOracle) yumUpdateInfo() bool {
return true
}
// root privilege isn't needed
func (o rootPrivOracle) yumChangelog() bool {
return false
}
func (o rootPrivOracle) yumMakeCache() bool {
return true
}

View File

@@ -22,7 +22,6 @@ import (
"fmt"
"regexp"
"strings"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
@@ -142,9 +141,6 @@ type redhatBase struct {
type rootPriv interface {
repoquery() bool
yumRepolist() bool
yumUpdateInfo() bool
yumChangelog() bool
yumMakeCache() bool
}
@@ -237,12 +233,7 @@ func (o *redhatBase) scanPackages() error {
}
if o.getServerInfo().Mode.IsOffline() {
switch o.Distro.Family {
case config.Amazon:
// nop
default:
return nil
}
return nil
} else if o.Distro.Family == config.RedHat {
if o.getServerInfo().Mode.IsFast() {
return nil
@@ -259,13 +250,6 @@ func (o *redhatBase) scanPackages() error {
installed.MergeNewVersion(updatable)
o.Packages = installed
}
var unsecures models.VulnInfos
if unsecures, err = o.scanUnsecurePackages(updatable); err != nil {
o.log.Errorf("Failed to scan vulnerable packages: %s", err)
return err
}
o.VulnInfos = unsecures
return nil
}
@@ -457,24 +441,6 @@ func (o *redhatBase) isExecScanUsingYum() bool {
return true
}
func (o *redhatBase) isExecFillChangelogs() bool {
if o.getServerInfo().Mode.IsOffline() {
return false
}
// Amazon linux has no changelos for updates
return o.getServerInfo().Mode.IsDeep() &&
o.Distro.Family != config.Amazon
}
func (o *redhatBase) isExecScanChangelogs() bool {
if o.getServerInfo().Mode.IsOffline() ||
o.getServerInfo().Mode.IsFast() ||
o.getServerInfo().Mode.IsFastRoot() {
return false
}
return true
}
func (o *redhatBase) isExecYumPS() bool {
// RedHat has no yum-ps
switch o.Distro.Family {
@@ -526,658 +492,6 @@ func (o *redhatBase) isExecNeedsRestarting() bool {
return true
}
func (o *redhatBase) scanUnsecurePackages(updatable models.Packages) (models.VulnInfos, error) {
if o.isExecFillChangelogs() {
if err := o.fillChangelogs(updatable); err != nil {
err = xerrors.Errorf("Failed to fetch changelogs: %w", err)
o.log.Warnf("err: %+v", err)
o.warns = append(o.warns, err)
// Only warning this error
}
}
if o.isExecScanUsingYum() {
return o.scanUsingYum(updatable)
}
// Parse changelog because CentOS does not have security channel...
if o.isExecScanChangelogs() {
return o.scanChangelogs(updatable)
}
return models.VulnInfos{}, nil
}
func (o *redhatBase) fillChangelogs(updatables models.Packages) error {
names := []string{}
for name := range updatables {
names = append(names, name)
}
if err := o.fillDiffChangelogs(names); err != nil {
return err
}
emptyChangelogPackNames := []string{}
for _, name := range names {
if o.Packages[name].Changelog.Contents == "" {
emptyChangelogPackNames = append(emptyChangelogPackNames, name)
}
}
i := 0
for _, name := range emptyChangelogPackNames {
i++
o.log.Infof("(%d/%d) Fetched Changelogs %s", i, len(emptyChangelogPackNames), name)
if err := o.fillDiffChangelogs([]string{name}); err != nil {
return err
}
}
return nil
}
func (o *redhatBase) getAvailableChangelogs(packNames []string) (map[string]string, error) {
yumopts := ""
if 0 < len(o.getServerInfo().Enablerepo) {
yumopts = " --enablerepo=" + strings.Join(o.getServerInfo().Enablerepo, ",")
}
if config.Conf.SkipBroken {
yumopts += " --skip-broken"
}
if o.hasYumColorOption() {
yumopts += " --color=never"
}
cmd := `yum changelog all updates %s %s | grep -A 1000000 "==================== Updated Packages ===================="`
cmd = fmt.Sprintf(cmd, yumopts, strings.Join(packNames, " "))
r := o.exec(util.PrependProxyEnv(cmd), o.sudo.yumChangelog())
if !r.isSuccess(0, 1) {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
return o.divideChangelogsIntoEachPackages(r.Stdout), nil
}
// Divide available change logs of all updatable packages into each package's changelog
func (o *redhatBase) divideChangelogsIntoEachPackages(stdout string) map[string]string {
changelogs := make(map[string]string)
scanner := bufio.NewScanner(strings.NewReader(stdout))
crlf, newBlock := false, true
packNameVer, contents := "", []string{}
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "==================== Updated Packages ====================") {
continue
}
if len(strings.TrimSpace(line)) != 0 && newBlock {
left := strings.Fields(line)[0]
// ss := strings.Split(left, ".")
// packNameVer = strings.Join(ss[0:len(ss)-1], ".")
packNameVer = left
newBlock = false
continue
}
if len(strings.TrimSpace(line)) == 0 {
if crlf {
changelogs[packNameVer] = strings.Join(contents, "\n")
packNameVer = ""
contents = []string{}
newBlock = true
crlf = false
} else {
contents = append(contents, line)
crlf = true
}
} else {
contents = append(contents, line)
crlf = false
}
}
if 0 < len(contents) {
changelogs[packNameVer] = strings.Join(contents, "\n")
}
return changelogs
}
func (o *redhatBase) fillDiffChangelogs(packNames []string) error {
changelogs, err := o.getAvailableChangelogs(packNames)
if err != nil {
return err
}
for s := range changelogs {
// name, pack, found := o.Packages.FindOne(func(p models.Package) bool {
name, pack, found := o.Packages.FindOne(func(p models.Package) bool {
var epochNameVerRel string
if index := strings.Index(p.NewVersion, ":"); 0 < index {
epoch := p.NewVersion[0:index]
ver := p.NewVersion[index+1 : len(p.NewVersion)]
epochNameVerRel = fmt.Sprintf("%s:%s-%s", epoch, p.Name, ver)
} else {
epochNameVerRel = fmt.Sprintf("%s-%s", p.Name, p.NewVersion)
}
return strings.HasPrefix(s, epochNameVerRel)
})
if found {
var detectionMethod string
diff, err := o.getDiffChangelog(pack, changelogs[s])
if err == nil {
detectionMethod = models.ChangelogExactMatchStr
} else {
o.log.Debug(err)
// Try without epoch
if index := strings.Index(pack.Version, ":"); 0 < index {
pack.Version = pack.Version[index+1 : len(pack.Version)]
o.log.Debug("Try without epoch", pack)
diff, err = o.getDiffChangelog(pack, changelogs[s])
if err != nil {
o.log.Debugf("Failed to find the version in changelog: %s-%s-%s",
pack.Name, pack.Version, pack.Release)
if len(diff) == 0 {
detectionMethod = models.FailedToGetChangelog
} else {
detectionMethod = models.FailedToFindVersionInChangelog
diff = ""
}
} else {
o.log.Debugf("Found the version in changelog without epoch: %s-%s-%s",
pack.Name, pack.Version, pack.Release)
detectionMethod = models.ChangelogLenientMatchStr
}
} else {
if len(diff) == 0 {
detectionMethod = models.FailedToGetChangelog
} else {
detectionMethod = models.FailedToFindVersionInChangelog
diff = ""
}
}
}
pack = o.Packages[name]
pack.Changelog = models.Changelog{
Contents: diff,
Method: models.DetectionMethod(detectionMethod),
}
o.Packages[name] = pack
}
}
return nil
}
func (o *redhatBase) getDiffChangelog(pack models.Package, availableChangelog string) (string, error) {
installedVer := ver.NewVersion(fmt.Sprintf("%s-%s", pack.Version, pack.Release))
scanner := bufio.NewScanner(strings.NewReader(availableChangelog))
diff := []string{}
found := false
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "* ") {
diff = append(diff, line)
continue
}
// openssh on RHEL
// openssh-server-6.6.1p1-35.el7_3.x86_64 rhui-rhel-7-server-rhui-rpms
// Wed Mar 1 21:00:00 2017 Jakub Jelen <jjelen@redhat.com> - 6.6.1p1-35 + 0.9.3-9
ss := strings.Split(line, " + ")
if 1 < len(ss) {
line = ss[0]
}
ss = strings.Split(line, " ")
if len(ss) < 2 {
diff = append(diff, line)
continue
}
v := ss[len(ss)-1]
v = strings.TrimPrefix(v, "-")
v = strings.TrimPrefix(v, "[")
v = strings.TrimSuffix(v, "]")
// On Amazon often end with email address. <aaa@aaa.com> Go to next line
if strings.HasPrefix(v, "<") && strings.HasSuffix(v, ">") {
diff = append(diff, line)
continue
}
version := ver.NewVersion(v)
if installedVer.Equal(version) || installedVer.GreaterThan(version) {
found = true
break
}
diff = append(diff, line)
}
if len(diff) == 0 || !found {
return availableChangelog,
xerrors.Errorf("Failed to find the version in changelog: %s-%s-%s",
pack.Name, pack.Version, pack.Release)
}
return strings.TrimSpace(strings.Join(diff, "\n")), nil
}
func (o *redhatBase) scanChangelogs(updatable models.Packages) (models.VulnInfos, error) {
packCveIDs := make(map[string][]string)
for name := range updatable {
cveIDs := []string{}
pack := o.Packages[name]
if pack.Changelog.Method == models.FailedToFindVersionInChangelog {
continue
}
scanner := bufio.NewScanner(strings.NewReader(pack.Changelog.Contents))
for scanner.Scan() {
if matches := cveRe.FindAllString(scanner.Text(), -1); 0 < len(matches) {
for _, m := range matches {
cveIDs = util.AppendIfMissing(cveIDs, m)
}
}
}
packCveIDs[name] = cveIDs
}
// transform datastructure
// - From
// "packname": []{"CVE-2017-1111", ".../
//
// - To
// map {
// "CVE-2017-1111": "packname",
// }
vinfos := models.VulnInfos{}
for name, cveIDs := range packCveIDs {
for _, cid := range cveIDs {
if v, ok := vinfos[cid]; ok {
v.AffectedPackages = append(v.AffectedPackages, models.PackageFixStatus{Name: name})
vinfos[cid] = v
} else {
vinfos[cid] = models.VulnInfo{
CveID: cid,
AffectedPackages: models.PackageFixStatuses{{Name: name}},
Confidences: models.Confidences{models.ChangelogExactMatch},
}
}
}
}
return vinfos, nil
}
type distroAdvisoryCveIDs struct {
DistroAdvisory models.DistroAdvisory
CveIDs []string
}
// Scaning unsecure packages using yum-plugin-security.
// Amazon, RHEL, Oracle Linux
func (o *redhatBase) scanUsingYum(updatable models.Packages) (models.VulnInfos, error) {
if o.Distro.Family == config.CentOS {
// CentOS has no security channel.
return nil, xerrors.New(
"yum updateinfo is not suppported on CentOS")
}
// get advisoryID(RHSA, ALAS, ELSA) - package name,version
major, err := (o.Distro.MajorVersion())
if err != nil {
return nil, xerrors.Errorf("Not implemented yet: %s, err: %w", o.Distro, err)
}
var cmd string
if (o.Distro.Family == config.RedHat || o.Distro.Family == config.Oracle) && major > 5 {
cmd = "yum repolist --color=never"
r := o.exec(util.PrependProxyEnv(cmd), o.sudo.yumRepolist())
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
}
if (o.Distro.Family == config.RedHat || o.Distro.Family == config.Oracle) && major == 5 {
cmd = "yum list-security --security"
if o.hasYumColorOption() {
cmd += " --color=never"
}
} else {
cmd = "yum updateinfo list updates --security --color=never"
}
r := o.exec(util.PrependProxyEnv(cmd), o.sudo.yumUpdateInfo())
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
advIDPackNamesList, err := o.parseYumUpdateinfoListAvailable(r.Stdout)
dict := make(map[string]models.Packages)
for _, advIDPackNames := range advIDPackNamesList {
packages := models.Packages{}
for _, packName := range advIDPackNames.PackNames {
pack, found := updatable[packName]
if !found {
return nil, xerrors.Errorf(
"Package not found. pack: %#v", packName)
}
packages[pack.Name] = pack
continue
}
dict[advIDPackNames.AdvisoryID] = packages
}
// get advisoryID(RHSA, ALAS, ELSA) - CVE IDs
if (o.Distro.Family == config.RedHat || o.Distro.Family == config.Oracle) && major == 5 {
cmd = "yum info-security"
if o.hasYumColorOption() {
cmd += " --color=never"
}
} else {
cmd = "yum updateinfo updates --security --color=never"
}
r = o.exec(util.PrependProxyEnv(cmd), o.sudo.yumUpdateInfo())
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
advisoryCveIDsList, err := o.parseYumUpdateinfo(r.Stdout)
if err != nil {
return nil, err
}
// All information collected.
// Convert to VulnInfos.
vinfos := models.VulnInfos{}
for _, advIDCveIDs := range advisoryCveIDsList {
for _, cveID := range advIDCveIDs.CveIDs {
vinfo, found := vinfos[cveID]
if found {
advAppended := append(vinfo.DistroAdvisories, advIDCveIDs.DistroAdvisory)
vinfo.DistroAdvisories = advAppended
packs := dict[advIDCveIDs.DistroAdvisory.AdvisoryID]
for _, pack := range packs {
vinfo.AffectedPackages = append(vinfo.AffectedPackages,
models.PackageFixStatus{Name: pack.Name})
}
} else {
packs := dict[advIDCveIDs.DistroAdvisory.AdvisoryID]
affected := models.PackageFixStatuses{}
for _, p := range packs {
affected = append(affected, models.PackageFixStatus{Name: p.Name})
}
vinfo = models.VulnInfo{
CveID: cveID,
DistroAdvisories: []models.DistroAdvisory{advIDCveIDs.DistroAdvisory},
AffectedPackages: affected,
Confidences: models.Confidences{models.YumUpdateSecurityMatch},
}
}
vinfos[cveID] = vinfo
}
}
return vinfos, nil
}
var horizontalRulePattern = regexp.MustCompile(`^=+$`)
func (o *redhatBase) parseYumUpdateinfo(stdout string) (result []distroAdvisoryCveIDs, err error) {
sectionState := Outside
lines := strings.Split(stdout, "\n")
lines = append(lines, "=============")
// Amazon Linux AMI Security Information
advisory := models.DistroAdvisory{}
cveIDsSetInThisSection := make(map[string]bool)
// use this flag to Collect CVE IDs in CVEs field.
inDesctiption, inCves := false, false
for _, line := range lines {
line = strings.TrimSpace(line)
// find the new section pattern
if horizontalRulePattern.MatchString(line) {
// set previous section's result to return-variable
if sectionState == Content {
foundCveIDs := []string{}
for cveID := range cveIDsSetInThisSection {
foundCveIDs = append(foundCveIDs, cveID)
}
result = append(result, distroAdvisoryCveIDs{
DistroAdvisory: advisory,
CveIDs: foundCveIDs,
})
// reset for next section.
cveIDsSetInThisSection = make(map[string]bool)
inDesctiption, inCves = false, false
advisory = models.DistroAdvisory{}
}
// Go to next section
sectionState = o.changeSectionState(sectionState)
continue
}
switch sectionState {
case Header:
switch o.Distro.Family {
case config.CentOS:
// CentOS has no security channel.
return result, xerrors.New(
"yum updateinfo is not suppported on CentOS")
case config.RedHat, config.Amazon, config.Oracle:
// nop
}
case Content:
if found := o.isDescriptionLine(line); found {
inDesctiption, inCves = true, false
ss := strings.Split(line, " : ")
advisory.Description += fmt.Sprintf("%s\n",
strings.Join(ss[1:], " : "))
continue
}
// severity
if severity, found := o.parseYumUpdateinfoToGetSeverity(line); found {
advisory.Severity = severity
continue
}
// No need to parse in description except severity
if inDesctiption {
if ss := strings.Split(line, ": "); 1 < len(ss) {
advisory.Description += fmt.Sprintf("%s\n",
strings.Join(ss[1:], ": "))
}
continue
}
if found := o.isCvesHeaderLine(line); found {
inCves = true
ss := strings.Split(line, "CVEs : ")
line = strings.Join(ss[1:], " ")
cveIDs := o.parseYumUpdateinfoLineToGetCveIDs(line)
for _, cveID := range cveIDs {
cveIDsSetInThisSection[cveID] = true
}
continue
}
if inCves {
cveIDs := o.parseYumUpdateinfoLineToGetCveIDs(line)
for _, cveID := range cveIDs {
cveIDsSetInThisSection[cveID] = true
}
}
advisoryID, found := o.parseYumUpdateinfoToGetAdvisoryID(line)
if found {
advisory.AdvisoryID = advisoryID
continue
}
issued, found := o.parseYumUpdateinfoLineToGetIssued(line)
if found {
advisory.Issued = issued
continue
}
updated, found := o.parseYumUpdateinfoLineToGetUpdated(line)
if found {
advisory.Updated = updated
continue
}
}
}
return
}
// state
const (
Outside = iota
Header = iota
Content = iota
)
func (o *redhatBase) changeSectionState(state int) (newState int) {
switch state {
case Outside, Content:
newState = Header
case Header:
newState = Content
}
return newState
}
func (o *redhatBase) isCvesHeaderLine(line string) bool {
return strings.Contains(line, "CVEs : ")
}
var yumCveIDPattern = regexp.MustCompile(`(CVE-\d{4}-\d{4,})`)
func (o *redhatBase) parseYumUpdateinfoLineToGetCveIDs(line string) []string {
return yumCveIDPattern.FindAllString(line, -1)
}
var yumAdvisoryIDPattern = regexp.MustCompile(`^ *Update ID : (.*)$`)
func (o *redhatBase) parseYumUpdateinfoToGetAdvisoryID(line string) (advisoryID string, found bool) {
result := yumAdvisoryIDPattern.FindStringSubmatch(line)
if len(result) != 2 {
return "", false
}
return strings.TrimSpace(result[1]), true
}
var yumIssuedPattern = regexp.MustCompile(`^\s*Issued : (\d{4}-\d{2}-\d{2})`)
func (o *redhatBase) parseYumUpdateinfoLineToGetIssued(line string) (date time.Time, found bool) {
return o.parseYumUpdateinfoLineToGetDate(line, yumIssuedPattern)
}
var yumUpdatedPattern = regexp.MustCompile(`^\s*Updated : (\d{4}-\d{2}-\d{2})`)
func (o *redhatBase) parseYumUpdateinfoLineToGetUpdated(line string) (date time.Time, found bool) {
return o.parseYumUpdateinfoLineToGetDate(line, yumUpdatedPattern)
}
func (o *redhatBase) parseYumUpdateinfoLineToGetDate(line string, regexpPattern *regexp.Regexp) (date time.Time, found bool) {
result := regexpPattern.FindStringSubmatch(line)
if len(result) != 2 {
return date, false
}
t, err := time.Parse("2006-01-02", result[1])
if err != nil {
return date, false
}
return t, true
}
var yumDescriptionPattern = regexp.MustCompile(`^\s*Description : `)
func (o *redhatBase) isDescriptionLine(line string) bool {
return yumDescriptionPattern.MatchString(line)
}
var yumSeverityPattern = regexp.MustCompile(`^ *Severity : (.*)$`)
func (o *redhatBase) parseYumUpdateinfoToGetSeverity(line string) (severity string, found bool) {
result := yumSeverityPattern.FindStringSubmatch(line)
if len(result) != 2 {
return "", false
}
return strings.TrimSpace(result[1]), true
}
type advisoryIDPacks struct {
AdvisoryID string
PackNames []string
}
type advisoryIDPacksList []advisoryIDPacks
func (list advisoryIDPacksList) find(advisoryID string) (advisoryIDPacks, bool) {
for _, a := range list {
if a.AdvisoryID == advisoryID {
return a, true
}
}
return advisoryIDPacks{}, false
}
func (o *redhatBase) extractPackNameVerRel(nameVerRel string) (name, ver, rel string) {
fields := strings.Split(nameVerRel, ".")
archTrimed := strings.Join(fields[0:len(fields)-1], ".")
fields = strings.Split(archTrimed, "-")
rel = fields[len(fields)-1]
ver = fields[len(fields)-2]
name = strings.Join(fields[0:(len(fields)-2)], "-")
return
}
// parseYumUpdateinfoListAvailable collect AdvisorID(RHSA, ALAS, ELSA), packages
func (o *redhatBase) parseYumUpdateinfoListAvailable(stdout string) (advisoryIDPacksList, error) {
result := []advisoryIDPacks{}
lines := strings.Split(stdout, "\n")
for _, line := range lines {
if !(strings.HasPrefix(line, "RHSA") ||
strings.HasPrefix(line, "ALAS") ||
strings.HasPrefix(line, "ELSA")) {
continue
}
fields := strings.Fields(line)
if len(fields) != 3 {
return []advisoryIDPacks{}, xerrors.Errorf(
"Unknown format. line: %s", line)
}
// extract fields
advisoryID := fields[0]
packVersion := fields[2]
packName, _, _ := o.extractPackNameVerRel(packVersion)
found := false
for i, s := range result {
if s.AdvisoryID == advisoryID {
names := s.PackNames
names = append(names, packName)
result[i].PackNames = names
found = true
break
}
}
if !found {
result = append(result, advisoryIDPacks{
AdvisoryID: advisoryID,
PackNames: []string{packName},
})
}
}
return result, nil
}
func (o *redhatBase) yumPS() error {
cmd := "LANGUAGE=en_US.UTF-8 yum info yum"
r := o.exec(util.PrependProxyEnv(cmd), noSudo)

File diff suppressed because it is too large Load Diff

View File

@@ -53,47 +53,11 @@ func (o *rhel) depsFastRoot() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
majorVersion, _ := o.Distro.MajorVersion()
switch majorVersion {
case 5:
return []string{
"yum-utils",
"yum-security",
}
case 6:
return []string{
"yum-utils",
"yum-plugin-security",
}
default:
return []string{
"yum-utils",
}
}
return []string{"yum-utils"}
}
func (o *rhel) depsDeep() []string {
majorVersion, _ := o.Distro.MajorVersion()
switch majorVersion {
case 5:
return []string{
"yum-utils",
"yum-security",
"yum-changelog",
}
case 6:
return []string{
"yum-utils",
"yum-plugin-security",
"yum-plugin-changelog",
}
default:
return []string{
"yum-utils",
"yum-plugin-changelog",
}
}
return o.depsFastRoot()
}
func (o *rhel) checkIfSudoNoPasswd() error {
@@ -118,25 +82,17 @@ func (o *rhel) sudoNoPasswdCmdsFastRoot() []cmd {
majorVersion, _ := o.Distro.MajorVersion()
if majorVersion < 6 {
return []cmd{
// {"needs-restarting", exitStatusZero},
{"yum repolist --color=never", exitStatusZero},
{"yum list-security --security --color=never", exitStatusZero},
{"yum info-security --color=never", exitStatusZero},
{"repoquery -h", exitStatusZero},
}
}
return []cmd{
{"yum repolist --color=never", exitStatusZero},
{"yum updateinfo list updates --security --color=never", exitStatusZero},
{"yum updateinfo updates --security --color=never ", exitStatusZero},
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
}
}
func (o *rhel) sudoNoPasswdCmdsDeep() []cmd {
return append(o.sudoNoPasswdCmdsFastRoot(),
cmd{"yum changelog all updates --color=never", exitStatusZero})
return o.sudoNoPasswdCmdsFastRoot()
}
type rootPrivRHEL struct{}
@@ -145,18 +101,6 @@ func (o rootPrivRHEL) repoquery() bool {
return true
}
func (o rootPrivRHEL) yumRepolist() bool {
return true
}
func (o rootPrivRHEL) yumUpdateInfo() bool {
return true
}
func (o rootPrivRHEL) yumChangelog() bool {
return true
}
func (o rootPrivRHEL) yumMakeCache() bool {
return true
}