diff --git a/README.md b/README.md index c9c189cd..5a34d0c1 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/go.sum b/go.sum index 64aa3e11..4f80fe46 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/oval/redhat.go b/oval/redhat.go index 7bc860a8..3218385c 100644 --- a/oval/redhat.go +++ b/oval/redhat.go @@ -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) } diff --git a/report/report.go b/report/report.go index 0033e60c..c8cd6f46 100644 --- a/report/report.go +++ b/report/report.go @@ -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) diff --git a/scan/amazon.go b/scan/amazon.go index fa57e4a5..faa908ff 100644 --- a/scan/amazon.go +++ b/scan/amazon.go @@ -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 } diff --git a/scan/centos.go b/scan/centos.go index 95d9ee0a..7c00fd1a 100644 --- a/scan/centos.go +++ b/scan/centos.go @@ -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 } diff --git a/scan/oracle.go b/scan/oracle.go index b646a7e6..2b6d876b 100644 --- a/scan/oracle.go +++ b/scan/oracle.go @@ -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 } diff --git a/scan/redhatbase.go b/scan/redhatbase.go index ec8ba1c2..7f16923c 100644 --- a/scan/redhatbase.go +++ b/scan/redhatbase.go @@ -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 - 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. 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) diff --git a/scan/redhatbase_test.go b/scan/redhatbase_test.go index 7d1401f2..6f358e90 100644 --- a/scan/redhatbase_test.go +++ b/scan/redhatbase_test.go @@ -17,10 +17,7 @@ package scan import ( "reflect" - "sort" - "strings" "testing" - "time" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" @@ -154,547 +151,6 @@ func TestParseScanedPackagesLineRedhat(t *testing.T) { } -func TestChangeSectionState(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - oldState int - newState int - }{ - {Outside, Header}, - {Header, Content}, - {Content, Header}, - } - - for _, tt := range tests { - if n := r.changeSectionState(tt.oldState); n != tt.newState { - t.Errorf("expected %d, actual %d", tt.newState, n) - } - } -} - -func TestParseYumUpdateinfoLineToGetCveIDs(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - out []string - }{ - { - "Bugs : 1194651 - CVE-2015-0278 libuv:", - []string{"CVE-2015-0278"}, - }, - { - ": 1195457 - nodejs-0.10.35 causes undefined symbolsCVE-2015-0278, CVE-2015-0278, CVE-2015-02770000000 ", - []string{ - "CVE-2015-0278", - "CVE-2015-0278", - "CVE-2015-02770000000", - }, - }, - } - - for _, tt := range tests { - act := r.parseYumUpdateinfoLineToGetCveIDs(tt.in) - for i, s := range act { - if s != tt.out[i] { - t.Errorf("expected %s, actual %s", tt.out[i], s) - } - } - } -} - -func TestParseYumUpdateinfoToGetAdvisoryID(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - out string - found bool - }{ - { - "Update ID : RHSA-2015:2315", - "RHSA-2015:2315", - true, - }, - { - "Update ID : ALAS-2015-620", - "ALAS-2015-620", - true, - }, - { - "Issued : 2015-11-19 00:00:00", - "", - false, - }, - } - - for _, tt := range tests { - advisoryID, found := r.parseYumUpdateinfoToGetAdvisoryID(tt.in) - if tt.out != advisoryID { - t.Errorf("expected %s, actual %s", tt.out, advisoryID) - } - if tt.found != found { - t.Errorf("expected %t, actual %t", tt.found, found) - } - } -} - -func TestParseYumUpdateinfoLineToGetIssued(t *testing.T) { - - date, _ := time.Parse("2006-01-02", "2015-12-15") - - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - out time.Time - found bool - }{ - { - "Issued : 2015-12-15 00:00:00", - date, - true, - }, - { - " Issued : 2015-12-15 00:00:00 ", - date, - true, - }, - { - "Type : security", - time.Time{}, - false, - }, - } - - for i, tt := range tests { - d, found := r.parseYumUpdateinfoLineToGetIssued(tt.in) - if tt.found != found { - t.Errorf("[%d] line: %s, expected %t, actual %t", i, tt.in, tt.found, found) - } - if tt.out != d { - t.Errorf("[%d] line: %s, expected %v, actual %v", i, tt.in, tt.out, d) - } - } -} - -func TestParseYumUpdateinfoLineToGetUpdated(t *testing.T) { - date, _ := time.Parse("2006-01-02", "2015-12-15") - - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - out time.Time - found bool - }{ - { - "Updated : 2015-12-15 00:00:00 Bugs : 1286966 - CVE-2015-8370 grub2: buffer overflow when checking password entered during bootup", - date, - true, - }, - { - - "Updated : 2015-12-15 14:16 CVEs : CVE-2015-7981", - date, - true, - }, - { - "Type : security", - time.Time{}, - false, - }, - } - - for i, tt := range tests { - d, found := r.parseYumUpdateinfoLineToGetUpdated(tt.in) - if tt.found != found { - t.Errorf("[%d] line: %s, expected %t, actual %t", i, tt.in, tt.found, found) - } - if tt.out != d { - t.Errorf("[%d] line: %s, expected %v, actual %v", i, tt.in, tt.out, d) - } - } -} - -func TestIsDescriptionLine(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - found bool - }{ - { - "Description : Package updates are available for Amazon Linux AMI that fix the", - true, - }, - { - " Description : Package updates are available for Amazon Linux AMI that fix the", - true, - }, - { - "Status : final", - false, - }, - } - - for i, tt := range tests { - found := r.isDescriptionLine(tt.in) - if tt.found != found { - t.Errorf("[%d] line: %s, expected %t, actual %t", i, tt.in, tt.found, found) - } - } -} - -func TestParseYumUpdateinfoToGetSeverity(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - in string - out string - found bool - }{ - { - "Severity : Moderate", - "Moderate", - true, - }, - { - " Severity : medium", - "medium", - true, - }, - { - "Status : final", - "", - false, - }, - } - - for i, tt := range tests { - out, found := r.parseYumUpdateinfoToGetSeverity(tt.in) - if tt.found != found { - t.Errorf("[%d] line: %s, expected %t, actual %t", i, tt.in, tt.found, found) - } - if tt.out != out { - t.Errorf("[%d] line: %s, expected %v, actual %v", i, tt.in, tt.out, out) - } - } -} - -func TestParseYumUpdateinfoOL(t *testing.T) { - stdout := `=============================================================================== - bind security update -=============================================================================== - Update ID : ELSA-2017-0276 - Release : Oracle Linux 7 - Type : security - Status : final - Issued : 2017-02-15 - CVEs : CVE-2017-3135 -Description : [32:9.9.4-38.2] - Severity : Moderate - -=============================================================================== - openssl security update -=============================================================================== - Update ID : ELSA-2017-0286 - Release : Oracle Linux 7 - Type : security - Status : final - Issued : 2017-02-15 - CVEs : CVE-2016-8610 - : CVE-2017-3731 -Description : [1.0.1e-48.4] - Severity : Moderate - -=============================================================================== - Unbreakable Enterprise kernel security update -=============================================================================== - Update ID : ELSA-2017-3520 - Release : Oracle Linux 7 - Type : security - Status : final - Issued : 2017-02-15 - CVEs : CVE-2017-6074 -Description : kernel-uek - Severity : Important - - ` - issued, _ := time.Parse("2006-01-02", "2017-02-15") - - r := newRHEL(config.ServerInfo{}) - r.Distro = config.Distro{Family: "oraclelinux"} - - var tests = []struct { - in string - out []distroAdvisoryCveIDs - }{ - { - stdout, - []distroAdvisoryCveIDs{ - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "ELSA-2017-0276", - Severity: "Moderate", - Issued: issued, - Description: "[32:9.9.4-38.2]\n", - }, - CveIDs: []string{"CVE-2017-3135"}, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "ELSA-2017-0286", - Severity: "Moderate", - Issued: issued, - Description: "[1.0.1e-48.4]\n", - }, - CveIDs: []string{ - "CVE-2016-8610", - "CVE-2017-3731", - }, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "ELSA-2017-3520", - Severity: "Important", - Issued: issued, - Description: "kernel-uek\n", - }, - CveIDs: []string{"CVE-2017-6074"}, - }, - }, - }, - } - for _, tt := range tests { - actual, _ := r.parseYumUpdateinfo(tt.in) - for i, advisoryCveIDs := range actual { - if tt.out[i].DistroAdvisory != advisoryCveIDs.DistroAdvisory { - t.Errorf("[%d] Alas is not same. \nexpected: %s\nactual: %s", - i, tt.out[i].DistroAdvisory, advisoryCveIDs.DistroAdvisory) - } - sort.Strings(tt.out[i].CveIDs) - sort.Strings(advisoryCveIDs.CveIDs) - if !reflect.DeepEqual(tt.out[i].CveIDs, advisoryCveIDs.CveIDs) { - t.Errorf("[%d] Alas is not same. \nexpected: %s\nactual: %s", - i, tt.out[i].CveIDs, advisoryCveIDs.CveIDs) - } - } - } -} - -func TestParseYumUpdateinfoRHEL(t *testing.T) { - - stdout := `=============================================================================== - Important: bind security update -=============================================================================== - Update ID : RHSA-2015:1705 - Release : - Type : security - Status : final - Issued : 2015-09-03 00:00:00 - Bugs : 1259087 - CVE-2015-5722 bind: malformed DNSSEC key failed assertion denial of service - CVEs : CVE-2015-5722 -Description : The Berkeley Internet Name Domain (BIND) is an implementation of - Severity : Important - -=============================================================================== - Important: bind security update -=============================================================================== - Update ID : RHSA-2015:2655 - Release : - Type : security - Status : final - Issued : 2015-09-03 01:00:00 - Updated : 2015-09-04 00:00:00 - Bugs : 1291176 - CVE-2015-8000 bind: responses with a malformed class attribute can trigger an assertion failure in db.c - CVEs : CVE-2015-8000 - : CVE-2015-8001 -Description : The Berkeley Internet Name Domain (BIND) is an implementation of - Severity : Low - -=============================================================================== - Moderate: bind security update -=============================================================================== - Update ID : RHSA-2016:0073 - Release : - Type : security - Status : final - Issued : 2015-09-03 02:00:00 - Bugs : 1299364 - CVE-2015-8704 bind: specific APL data could trigger an INSIST in apl_42.c - CVEs : CVE-2015-8704 - : CVE-2015-8705 -Description : The Berkeley Internet Name Domain (BIND) is an implementation of - : CVE-2015-10000 - Severity : Moderate - -=============================================================================== - Moderate: sudo security update -=============================================================================== - Update ID : RHSA-2017:1574 - Release : 0 - Type : security - Status : final - Issued : 2015-09-03 02:00:00 - Bugs : 1459152 - CVE-2017-1000368 sudo: Privilege escalation via improper get_process_ttyname() parsing (insufficient fix for CVE-2017-1000367) CVEs : CVE-2017-1000368 -Description : The sudo packages contain the sudo utility which allows system - : administrators to provide certain users with the - Severity : Moderate - ` - issued, _ := time.Parse("2006-01-02", "2015-09-03") - updated, _ := time.Parse("2006-01-02", "2015-09-04") - - r := newRHEL(config.ServerInfo{}) - r.Distro = config.Distro{Family: "redhat"} - - var tests = []struct { - in string - out []distroAdvisoryCveIDs - }{ - { - stdout, - []distroAdvisoryCveIDs{ - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "RHSA-2015:1705", - Severity: "Important", - Issued: issued, - Description: "The Berkeley Internet Name Domain (BIND) is an implementation of\n", - }, - CveIDs: []string{"CVE-2015-5722"}, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "RHSA-2015:2655", - Severity: "Low", - Issued: issued, - Updated: updated, - Description: "The Berkeley Internet Name Domain (BIND) is an implementation of\n", - }, - CveIDs: []string{ - "CVE-2015-8000", - "CVE-2015-8001", - }, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "RHSA-2016:0073", - Severity: "Moderate", - Issued: issued, - Description: "The Berkeley Internet Name Domain (BIND) is an implementation of\nCVE-2015-10000\n", - }, - CveIDs: []string{ - "CVE-2015-8704", - "CVE-2015-8705", - }, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "RHSA-2017:1574", - Severity: "Moderate", - Issued: issued, - Description: "The sudo packages contain the sudo utility which allows system\nadministrators to provide certain users with the\n", - }, - CveIDs: []string{ - "CVE-2017-1000368", - }, - }, - }, - }, - } - for _, tt := range tests { - actual, _ := r.parseYumUpdateinfo(tt.in) - for i, advisoryCveIDs := range actual { - sort.Strings(tt.out[i].CveIDs) - sort.Strings(advisoryCveIDs.CveIDs) - if !reflect.DeepEqual(tt.out[i], advisoryCveIDs) { - e := pp.Sprintf("%v", tt.out[i]) - a := pp.Sprintf("%v", advisoryCveIDs) - t.Errorf("[%d] not same. \nexpected: %s\nactual: %s", - i, e, a) - } - } - } -} - -func TestParseYumUpdateinfoAmazon(t *testing.T) { - r := newAmazon(config.ServerInfo{}) - r.Distro = config.Distro{Family: "redhat"} - - issued, _ := time.Parse("2006-01-02", "2015-12-15") - // updated, _ := time.Parse("2006-01-02", "2015-12-16") - - var tests = []struct { - in string - out []distroAdvisoryCveIDs - }{ - { - `=============================================================================== - Amazon Linux AMI 2014.03 - ALAS-2016-644: medium priority package update for python-rsa -=============================================================================== - Update ID : ALAS-2016-644 - Release : - Type : security - Status : final - Issued : 2015-12-15 13:30 - CVEs : CVE-2016-1494 -Description : Package updates are available for Amazon Linux AMI that fix the - : CVE-20160-1111 - : hogehoge - Severity : medium - -=============================================================================== - Amazon Linux AMI 2014.03 - ALAS-2015-614: medium priority package update for openssl -=============================================================================== - Update ID : ALAS-2015-614 - Release : - Type : security - Status : final - Issued : 2015-12-15 10:00 - Updated : 2015-12-16 14:15 CVEs : CVE-2015-3194 - : CVE-2015-3195 - : CVE-2015-3196 -Description : Package updates are available for Amazon Linux AMI that fix the - : foo bar baz - : hoge fuga hega - Severity : medium`, - - []distroAdvisoryCveIDs{ - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "ALAS-2016-644", - Severity: "medium", - Issued: issued, - Description: "Package updates are available for Amazon Linux AMI that fix the\nCVE-20160-1111\nhogehoge\n", - }, - CveIDs: []string{"CVE-2016-1494"}, - }, - { - DistroAdvisory: models.DistroAdvisory{ - AdvisoryID: "ALAS-2015-614", - Severity: "medium", - Issued: issued, - Description: "Package updates are available for Amazon Linux AMI that fix the\nfoo bar baz\nhoge fuga hega\n", - }, - CveIDs: []string{ - "CVE-2015-3194", - "CVE-2015-3195", - "CVE-2015-3196", - }, - }, - }, - }, - } - - for _, tt := range tests { - actual, _ := r.parseYumUpdateinfo(tt.in) - for i, advisoryCveIDs := range actual { - sort.Strings(tt.out[i].CveIDs) - sort.Strings(actual[i].CveIDs) - if !reflect.DeepEqual(tt.out[i], advisoryCveIDs) { - e := pp.Sprintf("%v", tt.out[i]) - a := pp.Sprintf("%v", advisoryCveIDs) - t.Errorf("[%d] Alas is not same. expected %s, actual %s", - i, e, a) - } - } - } -} - func TestParseYumCheckUpdateLine(t *testing.T) { r := newCentOS(config.ServerInfo{}) r.Distro = config.Distro{Family: "centos"} @@ -873,510 +329,6 @@ if-not-architecture 0 100 200 amzn-main` } } -func TestParseYumUpdateinfoListAvailable(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - rhelStdout := `RHSA-2015:2315 Moderate/Sec. NetworkManager-1:1.0.6-27.el7.x86_64 -RHSA-2015:2315 Moderate/Sec. NetworkManager-config-server-1:1.0.6-27.el7.x86_64 -RHSA-2015:1705 Important/Sec. bind-libs-lite-32:9.9.4-18.el7_1.5.x86_64 -RHSA-2016:0176 Critical/Sec. glibc-2.17-106.el7_2.4.x86_64 -RHSA-2015:2401 Low/Sec. grub2-1:2.02-0.29.el7.x86_64 -RHSA-2015:2401 Low/Sec. grub2-tools-1:2.02-0.29.el7.x86_64 -updateinfo list done` - - var tests = []struct { - in string - out []advisoryIDPacks - }{ - { - rhelStdout, - []advisoryIDPacks{ - { - AdvisoryID: "RHSA-2015:2315", - PackNames: []string{ - "NetworkManager", - "NetworkManager-config-server", - }, - }, - { - AdvisoryID: "RHSA-2015:1705", - PackNames: []string{ - "bind-libs-lite", - }, - }, - { - AdvisoryID: "RHSA-2016:0176", - PackNames: []string{ - "glibc", - }, - }, - { - AdvisoryID: "RHSA-2015:2401", - PackNames: []string{ - "grub2", - "grub2-tools", - }, - }, - }, - }, - } - - for _, tt := range tests { - actual, err := r.parseYumUpdateinfoListAvailable(tt.in) - if err != nil { - t.Errorf("Error has occurred: %s", err) - return - } - - for i := range actual { - if !reflect.DeepEqual(actual[i], tt.out[i]) { - e := pp.Sprintf("%v", tt.out) - a := pp.Sprintf("%v", actual) - t.Errorf("[%d] expected: %s\nactual: %s", i, e, a) - } - } - } -} - -func TestExtractPackNameVerRel(t *testing.T) { - r := newAmazon(config.ServerInfo{}) - var tests = []struct { - in string - out []string - }{ - { - "openssh-server-6.2p2-8.45.amzn1.x86_64", - []string{"openssh-server", "6.2p2", "8.45.amzn1"}, - }, - { - "bind-libs-lite-32:9.9.4-29.el7_2.1.x86_64", - []string{"bind-libs-lite", "32:9.9.4", "29.el7_2.1"}, - }, - { - "glibc-2.17-106.el7_2.1.x86_64", - []string{"glibc", "2.17", "106.el7_2.1"}, - }, - } - - for _, tt := range tests { - name, ver, rel := r.extractPackNameVerRel(tt.in) - if tt.out[0] != name { - t.Errorf("name: expected %s, actual %s", tt.out[0], name) - } - if tt.out[1] != ver { - t.Errorf("ver: expected %s, actual %s", tt.out[1], ver) - } - if tt.out[2] != rel { - t.Errorf("ver: expected %s, actual %s", tt.out[2], rel) - } - } - -} - -func TestGetDiffChangelog(t *testing.T) { - r := newCentOS(config.ServerInfo{}) - type in struct { - pack models.Package - changelog string - } - - var tests = []struct { - in in - out string - }{ - // 0 - { - in: in{ - pack: models.Package{ - Version: "2017a", - Release: "1", - }, - changelog: `* Mon Mar 20 12:00:00 2017 Patsy Franklin - 2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017. - -* Thu Mar 2 12:00:00 2017 Patsy Franklin - 2017a-1 -- Rebase to tzdata-2017a - - Mongolia no longer observes DST. (BZ #1425222) - - Add upstream patch to fix over-runing of POSIX limit on zone abbreviations. -- Add zone1970.tab file to the install list. (BZ #1427694) - -* Wed Nov 23 12:00:00 2016 Patsy Franklin - 2016j-1 -- Rebase to tzdata-2016ij - - Saratov region of Russia is moving from +03 offset to +04 offset - on 2016-12-04.`, - }, - out: `* Mon Mar 20 12:00:00 2017 Patsy Franklin - 2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017.`, - }, - // 1 - { - in: in{ - pack: models.Package{ - Version: "2004e", - Release: "2", - }, - changelog: `* Mon Mar 20 12:00:00 2017 Patsy Franklin - 2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017. - -* Wed Nov 23 12:00:00 2016 Patsy Franklin - 2016j-1 -- Rebase to tzdata-2016ij - - Saratov region of Russia is moving from +03 offset to +04 offset - on 2016-12-04. - -* Mon Nov 29 12:00:00 2004 Jakub Jelinek 2004g-1 -- 2004g (#141107) -- updates for Cuba - -* Mon Oct 11 12:00:00 2004 Jakub Jelinek 2004e-2 -- 2004e (#135194) -- updates for Brazil, Uruguay and Argentina`, - }, - out: `* Mon Mar 20 12:00:00 2017 Patsy Franklin - 2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017. - -* Wed Nov 23 12:00:00 2016 Patsy Franklin - 2016j-1 -- Rebase to tzdata-2016ij - - Saratov region of Russia is moving from +03 offset to +04 offset - on 2016-12-04. - -* Mon Nov 29 12:00:00 2004 Jakub Jelinek 2004g-1 -- 2004g (#141107) -- updates for Cuba`, - }, - // 2 - { - in: in{ - pack: models.Package{ - Version: "2016j", - Release: "1", - }, - changelog: `* Mon Mar 20 12:00:00 2017 Patsy Franklin -2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017. - -* Wed Nov 23 12:00:00 2016 Patsy Franklin -2016j-1 -- Rebase to tzdata-2016ij - - Saratov region of Russia is moving from +03 offset to +04 offset - on 2016-12-04.`, - }, - out: `* Mon Mar 20 12:00:00 2017 Patsy Franklin -2017b-1 -- Rebase to tzdata-2017b. - - Haiti resumed DST on March 12, 2017.`, - }, - // 3 - { - in: in{ - pack: models.Package{ - Version: "3.10.0", - Release: "327.22.1.el7", - }, - changelog: `* Thu Jun 9 21:00:00 2016 Alexander Gordeev [3.10.0-327.22.2.el7] -- [infiniband] security: Restrict use of the write() interface (Don Dutile) [1332553 1316685] {CVE-2016-4565} - -* Mon May 16 21:00:00 2016 Alexander Gordeev [3.10.0-327.22.1.el7] -- [mm] mmu_notifier: fix memory corruption (Jerome Glisse) [1335727 1307042] -- [misc] cxl: Increase timeout for detection of AFU mmio hang (Steve Best) [1335419 1329682] -- [misc] cxl: Configure the PSL for two CAPI ports on POWER8NVL (Steve Best) [1336389 1278793]`, - }, - out: `* Thu Jun 9 21:00:00 2016 Alexander Gordeev [3.10.0-327.22.2.el7] -- [infiniband] security: Restrict use of the write() interface (Don Dutile) [1332553 1316685] {CVE-2016-4565}`, - }, - // 4 - { - in: in{ - pack: models.Package{ - Version: "6.6.1p1", - Release: "34", - }, - - changelog: `* Wed Mar 1 21:00:00 2017 Jakub Jelen - 6.6.1p1-35 + 0.9.3-9 -- Do not send SD_NOTIFY from forked childern (#1381997) - -* Fri Feb 24 21:00:00 2017 Jakub Jelen - 6.6.1p1-34 + 0.9.3-9 -- Add SD_NOTIFY code to help systemd to track running service (#1381997)`, - }, - out: `* Wed Mar 1 21:00:00 2017 Jakub Jelen - 6.6.1p1-35 -- Do not send SD_NOTIFY from forked childern (#1381997)`, - }, - // 5 - { - in: in{ - pack: models.Package{ - Version: "2.1.23", - Release: "15.el6", - }, - changelog: `* Fri Feb 27 12:00:00 2015 Jakub Jelen 2.1.23-15.2 -- Support AIX SASL GSSAPI (#1174315) - -* Tue Nov 18 12:00:00 2014 Petr Lautrbach 2.1.23-15.1 -- check a context value in sasl_gss_encode() (#1087221) - -* Mon Jun 23 12:00:00 2014 Petr Lautrbach 2.1.23-15 -- don't use " for saslauth user's description (#1081445) -- backport the ad_compat option (#994242) -- fixed a memory leak in the client side DIGEST-MD5 code (#838628)`, - }, - out: `* Fri Feb 27 12:00:00 2015 Jakub Jelen 2.1.23-15.2 -- Support AIX SASL GSSAPI (#1174315) - -* Tue Nov 18 12:00:00 2014 Petr Lautrbach 2.1.23-15.1 -- check a context value in sasl_gss_encode() (#1087221)`, - }, - // 6 - { - in: in{ - pack: models.Package{ - Version: "3.6.20", - Release: "1.el6", - }, - changelog: `* Wed Jul 29 12:00:00 2015 Jan Stanek - 3.6.20-1.2 -- Add patch for compiler warnings highlighted by rpmdiff. - Related: rhbz#1244727 - -* Wed Jul 22 12:00:00 2015 Viktor Jancik - 3.6.20-1.el6_7.1 -- fix for CVE-2015-3416 - Resolves: #1244727 - -* Tue Nov 17 12:00:00 2009 Panu Matilainen - 3.6.20-1 -- update to 3.6.20 (http://www.sqlite.org/releaselog/3_6_20.html) - -* Tue Oct 6 12:00:00 2009 Panu Matilainen - 3.6.18-1 -- update to 3.6.18 (http://www.sqlite.org/releaselog/3_6_18.html) -- drop no longer needed test-disabler patches`, - }, - out: `* Wed Jul 29 12:00:00 2015 Jan Stanek - 3.6.20-1.2 -- Add patch for compiler warnings highlighted by rpmdiff. - Related: rhbz#1244727 - -* Wed Jul 22 12:00:00 2015 Viktor Jancik - 3.6.20-1.el6_7.1 -- fix for CVE-2015-3416 - Resolves: #1244727`, - }, - /* - // 7 - { - in: in{ - pack: models.Package{ - Version: "2:7.4.160", - Release: "1.el7", - }, - changelog: `* Mon Dec 12 21:00:00 2016 Karsten Hopp 7.4.160-1.1 - - add fix for CVE-2016-1248 - - * Wed Jan 29 21:00:00 2014 Karsten Hopp 7.4.160-1 - - patchlevel 160 - - Resolves: rhbz#1059321`, - }, - out: `* Mon Dec 12 21:00:00 2016 Karsten Hopp 7.4.160-1.1 - - add fix for CVE-2016-1248`, - }, - // 8 - { - in: in{ - pack: models.Package{ - Version: "2:1.26", - Release: "29.el7", - }, - changelog: `* Mon Jun 20 21:00:00 2016 Pavel Raiskup - 1.26-31 - - avoid double free in selinux code (rhbz#1347396) - - * Thu Jun 4 21:00:00 2015 Pavel Raiskup - 1.26-30 - - don't mistakenly set default ACLs (#1220890) - - * Fri Jan 24 21:00:00 2014 Daniel Mach - 2:1.26-29 - - Mass rebuild 2014-01-24`, - }, - out: `* Mon Jun 20 21:00:00 2016 Pavel Raiskup - 1.26-31 - - avoid double free in selinux code (rhbz#1347396) - - * Thu Jun 4 21:00:00 2015 Pavel Raiskup - 1.26-30 - - don't mistakenly set default ACLs (#1220890)`, - }, - // 9 - { - in: in{ - pack: models.Package{ - Version: "1:1.0.1e", - Release: "51.el7_2.5", - }, - changelog: `* Mon Feb 6 21:00:00 2017 Tomáš Mráz 1.0.1e-60.1 - - fix CVE-2017-3731 - DoS via truncated packets with RC4-MD5 cipher - - fix CVE-2016-8610 - DoS of single-threaded servers via excessive alerts - - * Fri Dec 4 21:00:00 2015 Tomáš Mráz 1.0.1e-52 - - fix CVE-2015-3194 - certificate verify crash with missing PSS parameter - - fix CVE-2015-3195 - X509_ATTRIBUTE memory leak - - fix CVE-2015-3196 - race condition when handling PSK identity hint - - * Tue Jun 23 21:00:00 2015 Tomáš Mráz 1.0.1e-51 - - fix the CVE-2015-1791 fix (broken server side renegotiation)`, - }, - out: `* Mon Feb 6 21:00:00 2017 Tomáš Mráz 1.0.1e-60.1 - - fix CVE-2017-3731 - DoS via truncated packets with RC4-MD5 cipher - - fix CVE-2016-8610 - DoS of single-threaded servers via excessive alerts - - * Fri Dec 4 21:00:00 2015 Tomáš Mráz 1.0.1e-52 - - fix CVE-2015-3194 - certificate verify crash with missing PSS parameter - - fix CVE-2015-3195 - X509_ATTRIBUTE memory leak - - fix CVE-2015-3196 - race condition when handling PSK identity hint`, - }, - // 10 - { - in: in{ - pack: models.Package{ - Version: "1:5.5.47", - Release: "1.el7_2", - }, - changelog: `* Wed Sep 21 21:00:00 2016 Honza Horak - 5.5.52-1 - - Rebase to 5.5.52, that also include fix for CVE-2016-6662 - Resolves: #1377974 - - * Thu Feb 18 21:00:00 2016 Jakub Dorňák - 1:5.5.47-2 - - Add warning to /usr/lib/tmpfiles.d/mariadb.conf - Resolves: #1241623 - - * Wed Feb 3 21:00:00 2016 Jakub Dorňák - 1:5.5.47-1 - - Rebase to 5.5.47 - Also fixes: CVE-2015-4792 CVE-2015-4802 CVE-2015-4815 CVE-2015-4816 - CVE-2015-4819 CVE-2015-4826 CVE-2015-4830 CVE-2015-4836 CVE-2015-4858 - CVE-2015-4861 CVE-2015-4870 CVE-2015-4879 CVE-2015-4913 CVE-2015-7744 - CVE-2016-0505 CVE-2016-0546 CVE-2016-0596 CVE-2016-0597 CVE-2016-0598 - CVE-2016-0600 CVE-2016-0606 CVE-2016-0608 CVE-2016-0609 CVE-2016-0616 - CVE-2016-2047 - Resolves: #1300621`, - }, - out: `* Wed Sep 21 21:00:00 2016 Honza Horak - 5.5.52-1 - - Rebase to 5.5.52, that also include fix for CVE-2016-6662 - Resolves: #1377974 - - * Thu Feb 18 21:00:00 2016 Jakub Dorňák - 1:5.5.47-2 - - Add warning to /usr/lib/tmpfiles.d/mariadb.conf - Resolves: #1241623`, - }, - */ - // 11 - { - in: in{ - pack: models.Package{ - Version: "0.252", - Release: "8.1.el7", - }, - changelog: `* Thu Sep 29 21:00:00 2016 Vitezslav Crhonek - 0.252-8.4 -- Remove wrong entry from usb ids. - Resolves: #1380159 - -* Mon Sep 26 21:00:00 2016 Vitezslav Crhonek - 0.252-8.3 -- Updated pci, usb and vendor ids. -- Resolves: rhbz#1292382 - -* Tue Jun 28 21:00:00 2016 Michal Minar 0.252-8.2 -- Updated pci, usb and vendor ids. -- Resolves: rhbz#1292382 -- Resolves: rhbz#1291614 -- Resolves: rhbz#1324198 - -* Fri Oct 23 21:00:00 2015 Michal Minar 0.252-8.1 -- Updated pci, usb and vendor ids.`, - }, - out: `* Thu Sep 29 21:00:00 2016 Vitezslav Crhonek - 0.252-8.4 -- Remove wrong entry from usb ids. - Resolves: #1380159 - -* Mon Sep 26 21:00:00 2016 Vitezslav Crhonek - 0.252-8.3 -- Updated pci, usb and vendor ids. -- Resolves: rhbz#1292382 - -* Tue Jun 28 21:00:00 2016 Michal Minar 0.252-8.2 -- Updated pci, usb and vendor ids. -- Resolves: rhbz#1292382 -- Resolves: rhbz#1291614 -- Resolves: rhbz#1324198`, - }, - // 12 - { - in: in{ - pack: models.Package{ - Version: "1:2.02", - Release: "0.34.el7_2", - }, - changelog: `* Mon Aug 29 21:00:00 2016 Peter Jones - 2.02-0.44 -- Work around tftp servers that don't work with multiple consecutive slashes in - file paths. - Resolves: rhbz#1217243`, - }, - out: `* Mon Aug 29 21:00:00 2016 Peter Jones - 2.02-0.44 -- Work around tftp servers that don't work with multiple consecutive slashes in - file paths. - Resolves: rhbz#1217243`, - }, - } - - for i, tt := range tests { - diff, _ := r.getDiffChangelog(tt.in.pack, tt.in.changelog) - if tt.out != diff { - t.Errorf("[%d] name: expected \n%s\nactual \n%s", i, tt.out, diff) - } - } - -} - -func TestDivideChangelogsIntoEachPackages(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - type in struct { - pack models.Package - changelog string - } - - var tests = []struct { - in string - out map[string]string - }{ - { - in: `==================== Updated Packages ==================== -1:NetworkManager-1.4.0-20.el7_3.x86_64 rhui-rhel-7-server-rhui-rpms -* Mon Apr 24 21:00:00 2017 Beniamino Galvani - 1:1.4.0-20 -- vlan: use parent interface mtu as default (rh#1414186) - -* Wed Mar 29 21:00:00 2017 Beniamino Galvani - 1:1.4.0-19 -- core: alyways force a sync of the default route (rh#1431268) - - -1:NetworkManager-0.9.9.1-25.git20140326. rhui-rhel-7-server-rhui-optional-rpms -* Tue Jul 1 21:00:00 2014 Jiří Klimeš - 1:0.9.9.1-25.git20140326 -- core: fix MTU handling while merging/subtracting IP configs (rh #1093231) - -* Mon Jun 23 21:00:00 2014 Thomas Haller - 1:0.9.9.1-24.git20140326 -- core: fix crash on failure of reading bridge sysctl values (rh #1112020)`, - out: map[string]string{ - "1:NetworkManager-1.4.0-20.el7_3.x86_64": `* Mon Apr 24 21:00:00 2017 Beniamino Galvani - 1:1.4.0-20 -- vlan: use parent interface mtu as default (rh#1414186) - -* Wed Mar 29 21:00:00 2017 Beniamino Galvani - 1:1.4.0-19 -- core: alyways force a sync of the default route (rh#1431268)`, - - "1:NetworkManager-0.9.9.1-25.git20140326.": `* Tue Jul 1 21:00:00 2014 Jiří Klimeš - 1:0.9.9.1-25.git20140326 -- core: fix MTU handling while merging/subtracting IP configs (rh #1093231) - -* Mon Jun 23 21:00:00 2014 Thomas Haller - 1:0.9.9.1-24.git20140326 -- core: fix crash on failure of reading bridge sysctl values (rh #1112020)`, - }, - }, - } - - for _, tt := range tests { - changelogs := r.divideChangelogsIntoEachPackages(tt.in) - for k, v := range tt.out { - if strings.TrimSpace(v) != strings.TrimSpace(changelogs[k]) { - t.Errorf("expected: %v\nactual: %v", pp.Sprint(tt.out), pp.Sprint(changelogs)) - } - } - } - -} - func TestCheckYumPsInstalled(t *testing.T) { r := newCentOS(config.ServerInfo{}) var tests = []struct { @@ -1674,91 +626,3 @@ func TestIsExecScanUsingYum(t *testing.T) { } } } - -func TestIsExecFillChangelogs(t *testing.T) { - r := newRHEL(config.ServerInfo{}) - var tests = []struct { - modes []byte - family string - out bool - }{ - { - modes: []byte{config.Offline}, - out: false, - }, - { - modes: []byte{config.Deep}, - family: config.CentOS, - out: true, - }, - { - family: config.Amazon, - modes: []byte{config.Deep}, - out: false, - }, - { - modes: []byte{config.Deep}, - family: config.RedHat, - out: true, - }, - } - - for i, tt := range tests { - r.Distro.Family = tt.family - mode := config.ScanMode{} - for _, m := range tt.modes { - mode.Set(m) - } - - si := r.getServerInfo() - si.Mode = mode - r.setServerInfo(si) - out := r.isExecFillChangelogs() - if out != tt.out { - t.Errorf("[%d] expected %#v, actual %#v", i, tt.out, out) - } - } -} - -func TestIsScanChangelogs(t *testing.T) { - r := newCentOS(config.ServerInfo{}) - var tests = []struct { - modes []byte - family string - out bool - }{ - { - modes: []byte{config.Offline}, - out: false, - }, - { - modes: []byte{config.Fast}, - out: false, - }, - { - modes: []byte{config.FastRoot}, - out: false, - }, - { - modes: []byte{config.Deep}, - family: config.RedHat, - out: true, - }, - } - - for i, tt := range tests { - r.Distro.Family = tt.family - mode := config.ScanMode{} - for _, m := range tt.modes { - mode.Set(m) - } - - si := r.getServerInfo() - si.Mode = mode - r.setServerInfo(si) - out := r.isExecScanChangelogs() - if out != tt.out { - t.Errorf("[%d] expected %#v, actual %#v", i, tt.out, out) - } - } -} diff --git a/scan/rhel.go b/scan/rhel.go index c8d06184..84edabca 100644 --- a/scan/rhel.go +++ b/scan/rhel.go @@ -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 }