From b5cb08ac4384561e9dae001ba582f3fcfafd472f Mon Sep 17 00:00:00 2001 From: kota kanbe Date: Tue, 22 Aug 2017 17:44:50 +0900 Subject: [PATCH] Handle kernel's vulns using OVAL --- README.ja.md | 15 +++- README.md | 15 +++- models/scanresults.go | 14 +++- oval/debian.go | 181 ++++++++++++++++++++++++++++++++++-------- oval/oval.go | 5 +- oval/util.go | 43 ++++++---- report/report.go | 4 - scan/base.go | 60 +++++++------- scan/debian.go | 110 ++++++++++++++++--------- scan/debian_test.go | 162 +------------------------------------ scan/freebsd.go | 43 +++++++--- scan/redhat.go | 81 ++++++++++++++----- scan/redhat_test.go | 4 +- scan/serverapi.go | 9 +-- 14 files changed, 417 insertions(+), 329 deletions(-) diff --git a/README.ja.md b/README.ja.md index 620ba675..8ba6d3bd 100644 --- a/README.ja.md +++ b/README.ja.md @@ -767,6 +767,19 @@ configtest: configtestサブコマンドは、config.tomlで定義されたサーバ/コンテナに対してSSH可能かどうかをチェックする。 +## Fast Scan Mode + +| Distribution | Release | Requirements | +|:-------------|-------------------:|:-------------| +| Ubuntu | 12, 14, 16| - | +| Debian | 7, 8| reboot-notifier| +| CentOS | 6, 7| - | +| Amazon | All | - | +| RHEL | 5, 6, 7 | - | +| Oracle Linux | 5, 6, 7 | - | +| FreeBSD | 10, 11 | - | +| Raspbian | Jessie, Stretch | - | + ## Deep Scan Mode Deep Scan Modeではスキャン対象サーバ上にいくつかの依存パッケージが必要。 @@ -781,7 +794,7 @@ Deep Scan Modeでスキャンするためには、下記のパッケージが必 | Distribution | Release | Requirements | |:-------------|-------------------:|:-------------| | Ubuntu | 12, 14, 16| - | -| Debian | 7, 8| aptitude | +| Debian | 7, 8| aptitude, reboot-notifier | | CentOS | 6, 7| yum-plugin-changelog, yum-utils | | Amazon | All | yum-plugin-changelog, yum-utils | | RHEL | 5 | yum-utils, yum-security, yum-changelog | diff --git a/README.md b/README.md index d1682f41..57457401 100644 --- a/README.md +++ b/README.md @@ -776,6 +776,19 @@ configtest: The configtest subcommand checks whether vuls is able to connect via SSH to servers/containers defined in the config.toml + ## Fast Scan Mode + +| Distribution | Release | Requirements | +|:-------------|-------------------:|:-------------| +| Ubuntu | 12, 14, 16| - | +| Debian | 7, 8| reboot-notifier| +| CentOS | 6, 7| - | +| Amazon | All | - | +| RHEL | 5, 6, 7 | - | +| Oracle Linux | 5, 6, 7 | - | +| FreeBSD | 10, 11 | - | +| Raspbian | Jessie, Stretch | - | + ## Deep Scan Mode Some dependent packages are needed in Deep Scan Mode. @@ -788,7 +801,7 @@ In order to scan with deep scan mode, the following dependencies are required, s | Distribution | Release | Requirements | |:-------------|-------------------:|:-------------| | Ubuntu | 12, 14, 16| - | -| Debian | 7, 8| aptitude | +| Debian | 7, 8| aptitude, reboot-notifier | | CentOS | 6, 7| yum-plugin-changelog, yum-utils | | Amazon | All | yum-plugin-changelog, yum-utils | | RHEL | 5 | yum-utils, yum-security, yum-changelog | diff --git a/models/scanresults.go b/models/scanresults.go index 60024eab..f11b6ec0 100644 --- a/models/scanresults.go +++ b/models/scanresults.go @@ -44,9 +44,10 @@ type ScanResult struct { // Scanned Vulns by SSH scan + CPE + OVAL ScannedCves VulnInfos - Packages Packages - Errors []string - Optional [][]interface{} + RunningKernel Kernel + Packages Packages + Errors []string + Optional [][]interface{} Config struct { Scan config.Config @@ -54,6 +55,13 @@ type ScanResult struct { } } +// Kernel has the Release, version and whether need restart +type Kernel struct { + Release string + Version string + RebootRequired bool +} + // FilterByCvssOver is filter function. func (r ScanResult) FilterByCvssOver(over float64) ScanResult { filtered := r.ScannedCves.Find(func(v VulnInfo) bool { diff --git a/oval/debian.go b/oval/debian.go index 7756bd79..873a824d 100644 --- a/oval/debian.go +++ b/oval/debian.go @@ -29,40 +29,6 @@ type DebianBase struct { Base } -// FillWithOval returns scan result after updating CVE info by OVAL -func (o DebianBase) FillWithOval(r *models.ScanResult) (err error) { - var relatedDefs ovalResult - if o.isFetchViaHTTP() { - if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil { - return err - } - } else { - if relatedDefs, err = getDefsByPackNameFromOvalDB(o.family, r.Release, r.Packages); err != nil { - return err - } - } - - for _, defPacks := range relatedDefs.entries { - o.update(r, defPacks) - } - - for _, vuln := range r.ScannedCves { - switch models.NewCveContentType(o.family) { - case models.Debian: - if cont, ok := vuln.CveContents[models.Debian]; ok { - cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID - vuln.CveContents[models.Debian] = cont - } - case models.Ubuntu: - if cont, ok := vuln.CveContents[models.Ubuntu]; ok { - cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID - vuln.CveContents[models.Ubuntu] = cont - } - } - } - return nil -} - func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) { ovalContent := *o.convertToModel(&defPacks.def) ovalContent.Type = models.NewCveContentType(o.family) @@ -136,6 +102,57 @@ func NewDebian() Debian { } } +// FillWithOval returns scan result after updating CVE info by OVAL +func (o Debian) FillWithOval(r *models.ScanResult) (err error) { + + //Debian's uname gives both of kernel release(uname -r), version(kernel-image version) + linuxImage := "linux-image-" + r.RunningKernel.Release + // Add linux and set the version of running kernel to search OVAL. + if r.Container.ContainerID == "" { + r.Packages["linux"] = models.Package{ + Name: "linux", + Version: r.RunningKernel.Version, + } + } + + var relatedDefs ovalResult + if o.isFetchViaHTTP() { + if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil { + return err + } + } else { + if relatedDefs, err = getDefsByPackNameFromOvalDB(o.family, r.Release, r.Packages); err != nil { + return err + } + } + + delete(r.Packages, "linux") + + for _, defPacks := range relatedDefs.entries { + // Remove linux added above to search for oval + // linux is not a real package name (key of affected packages in OVAL) + if _, ok := defPacks.actuallyAffectedPackNames["linux"]; ok { + defPacks.actuallyAffectedPackNames[linuxImage] = true + delete(defPacks.actuallyAffectedPackNames, "linux") + for i, p := range defPacks.def.AffectedPacks { + if p.Name == "linux" { + p.Name = linuxImage + defPacks.def.AffectedPacks[i] = p + } + } + } + o.update(r, defPacks) + } + + for _, vuln := range r.ScannedCves { + if cont, ok := vuln.CveContents[models.Debian]; ok { + cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID + vuln.CveContents[models.Debian] = cont + } + } + return nil +} + // Ubuntu is the interface for Debian OVAL type Ubuntu struct { DebianBase @@ -151,3 +168,99 @@ func NewUbuntu() Ubuntu { }, } } + +// FillWithOval returns scan result after updating CVE info by OVAL +func (o Ubuntu) FillWithOval(r *models.ScanResult) (err error) { + ovalKernelImageNames := []string{ + "linux-aws", + "linux-azure", + "linux-flo", + "linux-gcp", + "linux-gke", + "linux-goldfish", + "linux-hwe", + "linux-hwe-edge", + "linux-kvm", + "linux-mako", + "linux-raspi2", + "linux-snapdragon", + } + linuxImage := "linux-image-" + r.RunningKernel.Release + + found := false + if r.Container.ContainerID == "" { + for _, n := range ovalKernelImageNames { + if _, ok := r.Packages[n]; ok { + v, ok := r.Packages[linuxImage] + if ok { + // Set running kernel version + p := r.Packages[n] + p.Version = v.Version + p.NewVersion = v.NewVersion + r.Packages[n] = p + } else { + util.Log.Warnf("Running kernel image %s is not found: %s", + linuxImage, r.RunningKernel.Version) + } + found = true + break + } + } + + if !found { + // linux-generic is described as "linux" in Ubuntu's oval. + // Add "linux" and set the version of running kernel to search OVAL. + v, ok := r.Packages[linuxImage] + if ok { + r.Packages["linux"] = models.Package{ + Name: "linux", + Version: v.Version, + NewVersion: v.NewVersion, + } + } else { + util.Log.Warnf("%s is not found. Running: %s", + linuxImage, r.RunningKernel.Release) + } + } + } + + var relatedDefs ovalResult + if o.isFetchViaHTTP() { + if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil { + return err + } + } else { + if relatedDefs, err = getDefsByPackNameFromOvalDB(o.family, r.Release, r.Packages); err != nil { + return err + } + } + + if !found { + delete(r.Packages, "linux") + } + + for _, defPacks := range relatedDefs.entries { + + // Remove "linux" added above to search for oval + // "linux" is not a real package name (key of affected packages in OVAL) + if _, ok := defPacks.actuallyAffectedPackNames["linux"]; !found && ok { + defPacks.actuallyAffectedPackNames[linuxImage] = true + delete(defPacks.actuallyAffectedPackNames, "linux") + for i, p := range defPacks.def.AffectedPacks { + if p.Name == "linux" { + p.Name = linuxImage + defPacks.def.AffectedPacks[i] = p + } + } + } + o.update(r, defPacks) + } + + for _, vuln := range r.ScannedCves { + if cont, ok := vuln.CveContents[models.Ubuntu]; ok { + cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID + vuln.CveContents[models.Ubuntu] = cont + } + } + return nil +} diff --git a/oval/oval.go b/oval/oval.go index 591c8853..6fb3846b 100644 --- a/oval/oval.go +++ b/oval/oval.go @@ -146,8 +146,5 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) { func (b Base) isFetchViaHTTP() bool { // Default value of OvalDBType is sqlite3 - if config.Conf.OvalDBURL != "" && config.Conf.OvalDBType == "sqlite3" { - return true - } - return false + return config.Conf.OvalDBURL != "" && config.Conf.OvalDBType == "sqlite3" } diff --git a/oval/util.go b/oval/util.go index 0527756b..e6f9542d 100644 --- a/oval/util.go +++ b/oval/util.go @@ -58,7 +58,7 @@ func (e defPacks) toPackStatuses(family string, packs models.Packages) (ps model }) } - case config.CentOS: + case config.CentOS, config.Debian: // There are many packages that has been fixed in RedHat, but not been fixed in CentOS for name := range e.actuallyAffectedPackNames { pack, ok := packs[name] @@ -79,8 +79,7 @@ func (e defPacks) toPackStatuses(family string, packs models.Packages) (ps model return } - packNewVer := fmt.Sprintf("%s-%s", pack.NewVersion, pack.NewRelease) - if packNewVer == "" { + if pack.NewVersion == "" { // compare version: installed vs oval vera := rpmver.NewVersion(fmt.Sprintf("%s-%s", pack.Version, pack.Release)) verb := rpmver.NewVersion(ovalPackVer) @@ -94,6 +93,7 @@ func (e defPacks) toPackStatuses(family string, packs models.Packages) (ps model }) } else { // compare version: newVer vs oval + packNewVer := fmt.Sprintf("%s-%s", pack.NewVersion, pack.NewRelease) vera := rpmver.NewVersion(packNewVer) verb := rpmver.NewVersion(ovalPackVer) notFixedYet := false @@ -193,11 +193,15 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult) ( if res.pack.Name != p.Name { continue } + + if p.NotFixedYet { + relatedDefs.upsert(def, p.Name) + continue + } + if less, err := lessThan(r.Family, *res.pack, p); err != nil { - if !p.NotFixedYet { - util.Log.Debugf("Failed to parse versions: %s", err) - util.Log.Debugf("%#v\n%#v", *res.pack, p) - } + util.Log.Debugf("Failed to parse versions: %s", err) + util.Log.Debugf("%#v\n%#v", *res.pack, p) } else if less { relatedDefs.upsert(def, p.Name) } @@ -278,23 +282,28 @@ func getDefsByPackNameFromOvalDB(family, osRelease string, return } defer ovaldb.CloseDB() - for _, pack := range installedPacks { - definitions, err := ovaldb.GetByPackName(osRelease, pack.Name) + for _, installedPack := range installedPacks { + definitions, err := ovaldb.GetByPackName(osRelease, installedPack.Name) if err != nil { return relatedDefs, fmt.Errorf("Failed to get %s OVAL info by package name: %v", family, err) } for _, def := range definitions { - for _, p := range def.AffectedPacks { - if pack.Name != p.Name { + for _, ovalPack := range def.AffectedPacks { + if installedPack.Name != ovalPack.Name { continue } - if less, err := lessThan(family, pack, p); err != nil { - if !p.NotFixedYet { - util.Log.Debugf("Failed to parse versions: %s", err) - util.Log.Debugf("%#v\n%#v", pack, p) - } + + if ovalPack.NotFixedYet { + relatedDefs.upsert(def, installedPack.Name) + continue + } + + less, err := lessThan(family, installedPack, ovalPack) + if err != nil { + util.Log.Debugf("Failed to parse versions: %s", err) + util.Log.Debugf("%#v\n%#v", installedPack, ovalPack) } else if less { - relatedDefs.upsert(def, pack.Name) + relatedDefs.upsert(def, installedPack.Name) } } } diff --git a/report/report.go b/report/report.go index cd304885..4d07fd6c 100644 --- a/report/report.go +++ b/report/report.go @@ -170,10 +170,6 @@ func FillWithOval(r *models.ScanResult) (err error) { case c.Oracle: ovalClient = oval.NewOracle() ovalFamily = c.Oracle - //TODO - // case c.Suse: - // ovalClient = oval.New() - // ovalFamily = c.Oracle case c.Amazon, c.Raspbian, c.FreeBSD: return nil default: diff --git a/scan/base.go b/scan/base.go index 0f13b63e..ba02a346 100644 --- a/scan/base.go +++ b/scan/base.go @@ -75,6 +75,27 @@ func (l *base) getPlatform() models.Platform { return l.Platform } +func (l *base) runningKernel() (release, version string, err error) { + r := l.exec("uname -r", noSudo) + if !r.isSuccess() { + return "", "", fmt.Errorf("Failed to SSH: %s", r) + } + release = strings.TrimSpace(r.Stdout) + + switch l.Distro.Family { + case config.Debian: + r := l.exec("uname -a", noSudo) + if !r.isSuccess() { + return "", "", fmt.Errorf("Failed to SSH: %s", r) + } + ss := strings.Fields(r.Stdout) + if 6 < len(ss) { + version = ss[6] + } + } + return +} + func (l *base) allContainers() (containers []config.Container, err error) { switch l.ServerInfo.Containers.Type { case "", "docker": @@ -265,16 +286,6 @@ func (l *base) isAwsInstanceID(str string) bool { } func (l *base) convertToModel() models.ScanResult { - //TODO Remove - // for _, p := range l.VulnInfos { - // sort.Slice(p.Packages, func(i, j int) bool { - // return p.Packages[i].Name < p.Packages[j].Name - // }) - // } - // sort.Slice(l.VulnInfos, func(i, j int) bool { - // return l.VulnInfos[i].CveID < l.VulnInfos[j].CveID - // }) - ctype := l.ServerInfo.Containers.Type if l.ServerInfo.Container.ContainerID != "" && ctype == "" { ctype = "docker" @@ -291,24 +302,19 @@ func (l *base) convertToModel() models.ScanResult { errs = append(errs, fmt.Sprintf("%s", e)) } - //TODO Remove - // Avoid null slice being null in JSON - // for cveID := range l.VulnInfos { - // l.VulnInfos[i].NilToEmpty() - // } - return models.ScanResult{ - JSONVersion: models.JSONVersion, - ServerName: l.ServerInfo.ServerName, - ScannedAt: time.Now(), - Family: l.Distro.Family, - Release: l.Distro.Release, - Container: container, - Platform: l.Platform, - ScannedCves: l.VulnInfos, - Packages: l.Packages, - Optional: l.ServerInfo.Optional, - Errors: errs, + JSONVersion: models.JSONVersion, + ServerName: l.ServerInfo.ServerName, + ScannedAt: time.Now(), + Family: l.Distro.Family, + Release: l.Distro.Release, + Container: container, + Platform: l.Platform, + ScannedCves: l.VulnInfos, + RunningKernel: l.Kernel, + Packages: l.Packages, + Optional: l.ServerInfo.Optional, + Errors: errs, } } diff --git a/scan/debian.go b/scan/debian.go index 1e787b98..581f0917 100644 --- a/scan/debian.go +++ b/scan/debian.go @@ -154,56 +154,92 @@ func (o *debian) checkIfSudoNoPasswd() error { } func (o *debian) checkDependencies() error { - if !config.Conf.Deep { - o.log.Infof("Dependencies... No need") - return nil - } + packNames := []string{} + switch o.Distro.Family { case config.Ubuntu, config.Raspbian: o.log.Infof("Dependencies... No need") return nil case config.Debian: - // Debian needs aptitude to get changelogs. - // Because unable to get changelogs via apt-get changelog on Debian. - if r := o.exec("test -f /usr/bin/aptitude", noSudo); !r.isSuccess() { - msg := fmt.Sprintf("aptitude is not installed: %s", r) - o.log.Errorf(msg) - return fmt.Errorf(msg) + // https://askubuntu.com/a/742844 + packNames = append(packNames, "reboot-notifier") + + if !config.Conf.Deep { + // Debian needs aptitude to get changelogs. + // Because unable to get changelogs via apt-get changelog on Debian. + packNames = append(packNames, "aptitude") } - o.log.Infof("Dependencies... Pass") - return nil default: return fmt.Errorf("Not implemented yet: %s", o.Distro) } -} -func (o *debian) scanPackages() error { - installed, updatable, err := o.scanInstalledPackages() - if err != nil { - o.log.Errorf("Failed to scan installed packages") - return err - } - o.setPackages(installed) - - if config.Conf.Deep || o.Distro.Family == config.Raspbian { - unsecure, err := o.scanUnsecurePackages(updatable) - if err != nil { - o.log.Errorf("Failed to scan vulnerable packages") - return err + for _, name := range packNames { + //TODO --show-format + cmd := "dpkg-query -W " + name + if r := o.exec(cmd, noSudo); !r.isSuccess() { + msg := fmt.Sprintf("%s is not installed", name) + o.log.Errorf(msg) + return fmt.Errorf(msg) } - o.setVulnInfos(unsecure) - return nil } - + o.log.Infof("Dependencies... Pass") return nil } -func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, error) { - installed := models.Packages{} - updatable := models.Packages{} +func (o *debian) scanPackages() error { + // collect the running kernel information + release, version, err := o.runningKernel() + if err != nil { + o.log.Errorf("Failed to scan the running kernel version: %s", err) + return err + } + rebootRequired, err := o.rebootRequired() + if err != nil { + o.log.Errorf("Failed to detect the kernel reboot required: %s", err) + return err + } + o.Kernel = models.Kernel{ + Version: version, + Release: release, + RebootRequired: rebootRequired, + } + installed, updatable, err := o.scanInstalledPackages() + if err != nil { + o.log.Errorf("Failed to scan installed packages: %s", err) + return err + } + o.Packages = installed + + if config.Conf.Deep || o.Distro.Family == config.Raspbian { + unsecures, err := o.scanUnsecurePackages(updatable) + if err != nil { + o.log.Errorf("Failed to scan vulnerable packages: %s", err) + return err + } + o.VulnInfos = unsecures + return nil + } + return nil +} + +// https://askubuntu.com/a/742844 +func (o *debian) rebootRequired() (bool, error) { + r := o.exec("test -f /var/run/reboot-required", noSudo) + switch r.ExitStatus { + case 0: + return true, nil + case 1: + return false, nil + default: + return false, fmt.Errorf("Failed to check reboot reauired: %s", r) + } +} + +func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, error) { + installed, updatable := models.Packages{}, models.Packages{} r := o.exec("dpkg-query -W", noSudo) if !r.isSuccess() { return nil, nil, fmt.Errorf("Failed to SSH: %s", r) @@ -336,9 +372,9 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) { return &cached, nil } -func (o *debian) fillCandidateVersion(packages models.Packages) (err error) { +func (o *debian) fillCandidateVersion(updatables models.Packages) (err error) { names := []string{} - for name := range packages { + for name := range updatables { names = append(names, name) } cmd := fmt.Sprintf("LANGUAGE=en_US.UTF-8 apt-cache policy %s", strings.Join(names, " ")) @@ -352,18 +388,18 @@ func (o *debian) fillCandidateVersion(packages models.Packages) (err error) { if err != nil { return fmt.Errorf("Failed to parse %s", err) } - pack, ok := packages[k] + pack, ok := updatables[k] if !ok { return fmt.Errorf("Not found: %s", k) } pack.NewVersion = ver.Candidate - packages[k] = pack + updatables[k] = pack } return } func (o *debian) getUpdatablePackNames() (packNames []string, err error) { - cmd := util.PrependProxyEnv("LANGUAGE=en_US.UTF-8 apt-get upgrade --dry-run") + cmd := util.PrependProxyEnv("LANGUAGE=en_US.UTF-8 apt-get dist-upgrade --dry-run") r := o.exec(cmd, noSudo) if r.isSuccess(0, 1) { return o.parseAptGetUpgrade(r.Stdout) diff --git a/scan/debian_test.go b/scan/debian_test.go index 269214e9..f55f094f 100644 --- a/scan/debian_test.go +++ b/scan/debian_test.go @@ -303,49 +303,7 @@ Reading state information... Done The following packages will be upgraded: apt ca-certificates cpio dpkg e2fslibs e2fsprogs gnupg gpgv libc-bin libc6 libcomerr2 libpcre3 libpng12-0 libss2 libssl1.0.0 libudev0 multiarch-support openssl tzdata udev upstart -21 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. -Inst dpkg [1.16.1.2ubuntu7.5] (1.16.1.2ubuntu7.7 Ubuntu:12.04/precise-updates [amd64]) -Conf dpkg (1.16.1.2ubuntu7.7 Ubuntu:12.04/precise-updates [amd64]) -Inst upstart [1.5-0ubuntu7.2] (1.5-0ubuntu7.3 Ubuntu:12.04/precise-updates [amd64]) -Inst libc-bin [2.15-0ubuntu10.10] (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) [libc6:amd64 ] -Conf libc-bin (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) [libc6:amd64 ] -Inst libc6 [2.15-0ubuntu10.10] (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) -Conf libc6 (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) -Inst libudev0 [175-0ubuntu9.9] (175-0ubuntu9.10 Ubuntu:12.04/precise-updates [amd64]) -Inst tzdata [2015a-0ubuntu0.12.04] (2015g-0ubuntu0.12.04 Ubuntu:12.04/precise-updates [all]) -Conf tzdata (2015g-0ubuntu0.12.04 Ubuntu:12.04/precise-updates [all]) -Inst e2fslibs [1.42-1ubuntu2] (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) [e2fsprogs:amd64 on e2fslibs:amd64] [e2fsprogs:amd64 ] -Conf e2fslibs (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) [e2fsprogs:amd64 ] -Inst e2fsprogs [1.42-1ubuntu2] (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Conf e2fsprogs (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Inst gpgv [1.4.11-3ubuntu2.7] (1.4.11-3ubuntu2.9 Ubuntu:12.04/precise-updates [amd64]) -Conf gpgv (1.4.11-3ubuntu2.9 Ubuntu:12.04/precise-updates [amd64]) -Inst gnupg [1.4.11-3ubuntu2.7] (1.4.11-3ubuntu2.9 Ubuntu:12.04/precise-updates [amd64]) -Conf gnupg (1.4.11-3ubuntu2.9 Ubuntu:12.04/precise-updates [amd64]) -Inst apt [0.8.16~exp12ubuntu10.22] (0.8.16~exp12ubuntu10.26 Ubuntu:12.04/precise-updates [amd64]) -Conf apt (0.8.16~exp12ubuntu10.26 Ubuntu:12.04/precise-updates [amd64]) -Inst libcomerr2 [1.42-1ubuntu2] (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Conf libcomerr2 (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Inst libss2 [1.42-1ubuntu2] (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Conf libss2 (1.42-1ubuntu2.3 Ubuntu:12.04/precise-updates [amd64]) -Inst libssl1.0.0 [1.0.1-4ubuntu5.21] (1.0.1-4ubuntu5.34 Ubuntu:12.04/precise-updates [amd64]) -Conf libssl1.0.0 (1.0.1-4ubuntu5.34 Ubuntu:12.04/precise-updates [amd64]) -Inst libpcre3 [8.12-4] (8.12-4ubuntu0.1 Ubuntu:12.04/precise-updates [amd64]) -Inst libpng12-0 [1.2.46-3ubuntu4] (1.2.46-3ubuntu4.2 Ubuntu:12.04/precise-updates [amd64]) -Inst multiarch-support [2.15-0ubuntu10.10] (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) -Conf multiarch-support (2.15-0ubuntu10.13 Ubuntu:12.04/precise-updates [amd64]) -Inst cpio [2.11-7ubuntu3.1] (2.11-7ubuntu3.2 Ubuntu:12.04/precise-updates [amd64]) -Inst udev [175-0ubuntu9.9] (175-0ubuntu9.10 Ubuntu:12.04/precise-updates [amd64]) -Inst openssl [1.0.1-4ubuntu5.33] (1.0.1-4ubuntu5.34 Ubuntu:12.04/precise-updates [amd64]) -Inst ca-certificates [20141019ubuntu0.12.04.1] (20160104ubuntu0.12.04.1 Ubuntu:12.04/precise-updates [all]) -Conf libudev0 (175-0ubuntu9.10 Ubuntu:12.04/precise-updates [amd64]) -Conf upstart (1.5-0ubuntu7.3 Ubuntu:12.04/precise-updates [amd64]) -Conf libpcre3 (8.12-4ubuntu0.1 Ubuntu:12.04/precise-updates [amd64]) -Conf libpng12-0 (1.2.46-3ubuntu4.2 Ubuntu:12.04/precise-updates [amd64]) -Conf cpio (2.11-7ubuntu3.2 Ubuntu:12.04/precise-updates [amd64]) -Conf udev (175-0ubuntu9.10 Ubuntu:12.04/precise-updates [amd64]) -Conf openssl (1.0.1-4ubuntu5.34 Ubuntu:12.04/precise-updates [amd64]) -Conf ca-certificates (20160104ubuntu0.12.04.1 Ubuntu:12.04/precise-updates [all])`, +21 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.`, []string{ "apt", "ca-certificates", @@ -386,124 +344,6 @@ The following packages will be upgraded: ntpdate passwd python3.4 python3.4-minimal rsyslog sudo sysv-rc sysvinit-utils tzdata udev util-linux 59 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. -Inst base-files [7.2ubuntu5.2] (7.2ubuntu5.4 Ubuntu:14.04/trusty-updates [amd64]) -Conf base-files (7.2ubuntu5.4 Ubuntu:14.04/trusty-updates [amd64]) -Inst coreutils [8.21-1ubuntu5.1] (8.21-1ubuntu5.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf coreutils (8.21-1ubuntu5.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst dpkg [1.17.5ubuntu5.3] (1.17.5ubuntu5.5 Ubuntu:14.04/trusty-updates [amd64]) -Conf dpkg (1.17.5ubuntu5.5 Ubuntu:14.04/trusty-updates [amd64]) -Inst libc-bin [2.19-0ubuntu6.5] (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst libc6 [2.19-0ubuntu6.5] (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst libgcc1 [1:4.9.1-0ubuntu1] (1:4.9.3-0ubuntu4 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst gcc-4.9-base [4.9.1-0ubuntu1] (4.9.3-0ubuntu4 Ubuntu:14.04/trusty-updates [amd64]) -Conf gcc-4.9-base (4.9.3-0ubuntu4 Ubuntu:14.04/trusty-updates [amd64]) -Conf libgcc1 (1:4.9.3-0ubuntu4 Ubuntu:14.04/trusty-updates [amd64]) -Conf libc6 (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf libc-bin (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst e2fslibs [1.42.9-3ubuntu1] (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) [e2fsprogs:amd64 on e2fslibs:amd64] [e2fsprogs:amd64 ] -Conf e2fslibs (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) [e2fsprogs:amd64 ] -Inst e2fsprogs [1.42.9-3ubuntu1] (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf e2fsprogs (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst login [1:4.1.5.1-1ubuntu9] (1:4.1.5.1-1ubuntu9.2 Ubuntu:14.04/trusty-updates [amd64]) -Conf login (1:4.1.5.1-1ubuntu9.2 Ubuntu:14.04/trusty-updates [amd64]) -Inst mount [2.20.1-5.1ubuntu20.4] (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf mount (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst tzdata [2015a-0ubuntu0.14.04] (2015g-0ubuntu0.14.04 Ubuntu:14.04/trusty-updates [all]) -Conf tzdata (2015g-0ubuntu0.14.04 Ubuntu:14.04/trusty-updates [all]) -Inst sysvinit-utils [2.88dsf-41ubuntu6] (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst sysv-rc [2.88dsf-41ubuntu6] (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [all]) -Conf sysv-rc (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [all]) -Conf sysvinit-utils (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst util-linux [2.20.1-5.1ubuntu20.4] (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf util-linux (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst gcc-4.8-base [4.8.2-19ubuntu1] (4.8.4-2ubuntu1~14.04.1 Ubuntu:14.04/trusty-updates [amd64]) [libstdc++6:amd64 ] -Conf gcc-4.8-base (4.8.4-2ubuntu1~14.04.1 Ubuntu:14.04/trusty-updates [amd64]) [libstdc++6:amd64 ] -Inst libstdc++6 [4.8.2-19ubuntu1] (4.8.4-2ubuntu1~14.04.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libstdc++6 (4.8.4-2ubuntu1~14.04.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst libapt-pkg4.12 [1.0.1ubuntu2.6] (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Conf libapt-pkg4.12 (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Inst gpgv [1.4.16-1ubuntu2.1] (1.4.16-1ubuntu2.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf gpgv (1.4.16-1ubuntu2.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst gnupg [1.4.16-1ubuntu2.1] (1.4.16-1ubuntu2.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf gnupg (1.4.16-1ubuntu2.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst apt [1.0.1ubuntu2.6] (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Conf apt (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Inst bsdutils [1:2.20.1-5.1ubuntu20.4] (1:2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf bsdutils (1:2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst passwd [1:4.1.5.1-1ubuntu9] (1:4.1.5.1-1ubuntu9.2 Ubuntu:14.04/trusty-updates [amd64]) -Conf passwd (1:4.1.5.1-1ubuntu9.2 Ubuntu:14.04/trusty-updates [amd64]) -Inst libuuid1 [2.20.1-5.1ubuntu20.4] (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf libuuid1 (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst libblkid1 [2.20.1-5.1ubuntu20.4] (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf libblkid1 (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst libcomerr2 [1.42.9-3ubuntu1] (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libcomerr2 (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst libmount1 [2.20.1-5.1ubuntu20.4] (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf libmount1 (2.20.1-5.1ubuntu20.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst libpcre3 [1:8.31-2ubuntu2] (1:8.31-2ubuntu2.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libpcre3 (1:8.31-2ubuntu2.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst libss2 [1.42.9-3ubuntu1] (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libss2 (1.42.9-3ubuntu1.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst libapt-inst1.5 [1.0.1ubuntu2.6] (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Inst libexpat1 [2.1.0-4ubuntu1] (2.1.0-4ubuntu1.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst libffi6 [3.1~rc1+r3.0.13-12] (3.1~rc1+r3.0.13-12ubuntu0.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst libgcrypt11 [1.5.3-2ubuntu4.1] (1.5.3-2ubuntu4.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst libtasn1-6 [3.4-3ubuntu0.1] (3.4-3ubuntu0.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst libgnutls-openssl27 [2.12.23-12ubuntu2.1] (2.12.23-12ubuntu2.4 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst libgnutls26 [2.12.23-12ubuntu2.1] (2.12.23-12ubuntu2.4 Ubuntu:14.04/trusty-updates [amd64]) -Inst libsqlite3-0 [3.8.2-1ubuntu2] (3.8.2-1ubuntu2.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst python3.4 [3.4.0-2ubuntu1] (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst libpython3.4-stdlib [3.4.0-2ubuntu1] (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst python3.4-minimal [3.4.0-2ubuntu1] (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst libssl1.0.0 [1.0.1f-1ubuntu2.8] (1.0.1f-1ubuntu2.16 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst libpython3.4-minimal [3.4.0-2ubuntu1] (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst ntpdate [1:4.2.6.p5+dfsg-3ubuntu2.14.04.2] (1:4.2.6.p5+dfsg-3ubuntu2.14.04.8 Ubuntu:14.04/trusty-updates [amd64]) -Inst libdrm2 [2.4.56-1~ubuntu2] (2.4.64-1~ubuntu14.04.1 Ubuntu:14.04/trusty-updates [amd64]) -Inst libpng12-0 [1.2.50-1ubuntu2] (1.2.50-1ubuntu2.14.04.2 Ubuntu:14.04/trusty-updates [amd64]) -Inst initscripts [2.88dsf-41ubuntu6] (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst libcgmanager0 [0.24-0ubuntu7.3] (0.24-0ubuntu7.5 Ubuntu:14.04/trusty-updates [amd64]) -Inst udev [204-5ubuntu20.10] (204-5ubuntu20.18 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst libudev1 [204-5ubuntu20.10] (204-5ubuntu20.18 Ubuntu:14.04/trusty-updates [amd64]) -Inst multiarch-support [2.19-0ubuntu6.5] (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Conf multiarch-support (2.19-0ubuntu6.7 Ubuntu:14.04/trusty-updates [amd64]) -Inst apt-utils [1.0.1ubuntu2.6] (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Inst dh-python [1.20140128-1ubuntu8] (1.20140128-1ubuntu8.2 Ubuntu:14.04/trusty-updates [all]) -Inst iproute2 [3.12.0-2] (3.12.0-2ubuntu1 Ubuntu:14.04/trusty-updates [amd64]) -Inst ifupdown [0.7.47.2ubuntu4.1] (0.7.47.2ubuntu4.3 Ubuntu:14.04/trusty-updates [amd64]) -Inst isc-dhcp-client [4.2.4-7ubuntu12] (4.2.4-7ubuntu12.4 Ubuntu:14.04/trusty-updates [amd64]) [] -Inst isc-dhcp-common [4.2.4-7ubuntu12] (4.2.4-7ubuntu12.4 Ubuntu:14.04/trusty-updates [amd64]) -Inst rsyslog [7.4.4-1ubuntu2.5] (7.4.4-1ubuntu2.6 Ubuntu:14.04/trusty-updates [amd64]) -Inst sudo [1.8.9p5-1ubuntu1] (1.8.9p5-1ubuntu1.2 Ubuntu:14.04/trusty-updates [amd64]) -Inst cpio [2.11+dfsg-1ubuntu1.1] (2.11+dfsg-1ubuntu1.2 Ubuntu:14.04/trusty-updates [amd64]) -Conf libapt-inst1.5 (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Conf libexpat1 (2.1.0-4ubuntu1.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libffi6 (3.1~rc1+r3.0.13-12ubuntu0.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libgcrypt11 (1.5.3-2ubuntu4.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libtasn1-6 (3.4-3ubuntu0.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libgnutls26 (2.12.23-12ubuntu2.4 Ubuntu:14.04/trusty-updates [amd64]) -Conf libgnutls-openssl27 (2.12.23-12ubuntu2.4 Ubuntu:14.04/trusty-updates [amd64]) -Conf libsqlite3-0 (3.8.2-1ubuntu2.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libssl1.0.0 (1.0.1f-1ubuntu2.16 Ubuntu:14.04/trusty-updates [amd64]) -Conf libpython3.4-minimal (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf python3.4-minimal (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libpython3.4-stdlib (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf python3.4 (3.4.3-1ubuntu1~14.04.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf ntpdate (1:4.2.6.p5+dfsg-3ubuntu2.14.04.8 Ubuntu:14.04/trusty-updates [amd64]) -Conf libdrm2 (2.4.64-1~ubuntu14.04.1 Ubuntu:14.04/trusty-updates [amd64]) -Conf libpng12-0 (1.2.50-1ubuntu2.14.04.2 Ubuntu:14.04/trusty-updates [amd64]) -Conf initscripts (2.88dsf-41ubuntu6.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf libcgmanager0 (0.24-0ubuntu7.5 Ubuntu:14.04/trusty-updates [amd64]) -Conf libudev1 (204-5ubuntu20.18 Ubuntu:14.04/trusty-updates [amd64]) -Conf udev (204-5ubuntu20.18 Ubuntu:14.04/trusty-updates [amd64]) -Conf apt-utils (1.0.1ubuntu2.11 Ubuntu:14.04/trusty-updates [amd64]) -Conf dh-python (1.20140128-1ubuntu8.2 Ubuntu:14.04/trusty-updates [all]) -Conf iproute2 (3.12.0-2ubuntu1 Ubuntu:14.04/trusty-updates [amd64]) -Conf ifupdown (0.7.47.2ubuntu4.3 Ubuntu:14.04/trusty-updates [amd64]) -Conf isc-dhcp-common (4.2.4-7ubuntu12.4 Ubuntu:14.04/trusty-updates [amd64]) -Conf isc-dhcp-client (4.2.4-7ubuntu12.4 Ubuntu:14.04/trusty-updates [amd64]) -Conf rsyslog (7.4.4-1ubuntu2.6 Ubuntu:14.04/trusty-updates [amd64]) -Conf sudo (1.8.9p5-1ubuntu1.2 Ubuntu:14.04/trusty-updates [amd64]) -Conf cpio (2.11+dfsg-1ubuntu1.2 Ubuntu:14.04/trusty-updates [amd64]) `, []string{ "apt", diff --git a/scan/freebsd.go b/scan/freebsd.go index 597a83e1..8ac648fa 100644 --- a/scan/freebsd.go +++ b/scan/freebsd.go @@ -78,23 +78,48 @@ func (o *bsd) checkDependencies() error { } func (o *bsd) scanPackages() error { - var err error - var packs models.Packages - if packs, err = o.scanInstalledPackages(); err != nil { - o.log.Errorf("Failed to scan installed packages") + // collect the running kernel information + release, version, err := o.runningKernel() + if err != nil { + o.log.Errorf("Failed to scan the running kernel version: %s", err) return err } - o.setPackages(packs) + o.Kernel = models.Kernel{ + Release: release, + Version: version, + } - var vinfos models.VulnInfos - if vinfos, err = o.scanUnsecurePackages(); err != nil { - o.log.Errorf("Failed to scan vulnerable packages") + rebootRequired, err := o.rebootRequired() + if err != nil { + o.log.Errorf("Failed to detect the kernel reboot required: %s", err) return err } - o.setVulnInfos(vinfos) + o.Kernel.RebootRequired = rebootRequired + + packs, err := o.scanInstalledPackages() + if err != nil { + o.log.Errorf("Failed to scan installed packages: %s", err) + return err + } + o.Packages = packs + + unsecures, err := o.scanUnsecurePackages() + if err != nil { + o.log.Errorf("Failed to scan vulnerable packages: %s", err) + return err + } + o.VulnInfos = unsecures return nil } +func (o *bsd) rebootRequired() (bool, error) { + r := o.exec("freebsd-version -k", noSudo) + if !r.isSuccess() { + return false, fmt.Errorf("Failed to SSH: %s", r) + } + return o.Kernel.Release != strings.TrimSpace(r.Stdout), nil +} + func (o *bsd) scanInstalledPackages() (models.Packages, error) { cmd := util.PrependProxyEnv("pkg version -v") r := o.exec(cmd, noSudo) diff --git a/scan/redhat.go b/scan/redhat.go index f9243e73..0c75f388 100644 --- a/scan/redhat.go +++ b/scan/redhat.go @@ -223,32 +223,58 @@ func (o *redhat) checkDependencies() error { func (o *redhat) scanPackages() error { installed, err := o.scanInstalledPackages() if err != nil { - o.log.Errorf("Failed to scan installed packages") + o.log.Errorf("Failed to scan installed packages: %s", err) return err } + rebootRequired, err := o.rebootRequired() + if err != nil { + o.log.Errorf("Failed to detect the kernel reboot required: %s", err) + return err + } + o.Kernel.RebootRequired = rebootRequired + updatable, err := o.scanUpdatablePackages() if err != nil { - o.log.Errorf("Failed to scan installed packages") + o.log.Errorf("Failed to scan installed packages: %s", err) return err } installed.MergeNewVersion(updatable) - o.setPackages(installed) + o.Packages = installed if !config.Conf.Deep && o.Distro.Family != config.Amazon { return nil } - var vinfos models.VulnInfos - if vinfos, err = o.scanUnsecurePackages(updatable); err != nil { - o.log.Errorf("Failed to scan vulnerable packages") + 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.setVulnInfos(vinfos) + o.VulnInfos = unsecures return nil } +func (o *redhat) rebootRequired() (bool, error) { + r := o.exec("rpm -q --last kernel | head -n1", noSudo) + if !r.isSuccess() { + return false, fmt.Errorf("Failed to detect the last installed kernel : %v", r) + } + lastInstalledKernelVer := strings.Fields(r.Stdout)[0] + running := fmt.Sprintf("kernel-%s", o.Kernel.Release) + return running != lastInstalledKernelVer, nil +} + func (o *redhat) scanInstalledPackages() (models.Packages, error) { + release, version, err := o.runningKernel() + if err != nil { + return nil, err + } + o.Kernel = models.Kernel{ + Release: release, + Version: version, + } + installed := models.Packages{} var cmd string majorVersion, _ := o.Distro.MajorVersion() @@ -258,24 +284,35 @@ func (o *redhat) scanInstalledPackages() (models.Packages, error) { cmd = "rpm -qa --queryformat '%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH}\n'" } r := o.exec(cmd, noSudo) - if r.isSuccess() { - // openssl 0 1.0.1e 30.el6.11 x86_64 - lines := strings.Split(r.Stdout, "\n") - for _, line := range lines { - if trimed := strings.TrimSpace(line); len(trimed) != 0 { - pack, err := o.parseInstalledPackagesLine(line) - if err != nil { - return nil, err - } - installed[pack.Name] = pack - } - } - return installed, nil + if !r.isSuccess() { + return nil, fmt.Errorf("Scan packages failed: %s", r) } - return nil, fmt.Errorf("Scan packages failed. status: %d, stdout: %s, stderr: %s", - r.ExitStatus, r.Stdout, r.Stderr) + // openssl 0 1.0.1e 30.el6.11 x86_64 + lines := strings.Split(r.Stdout, "\n") + for _, line := range lines { + if trimed := strings.TrimSpace(line); len(trimed) != 0 { + pack, err := o.parseInstalledPackagesLine(line) + if err != nil { + return nil, err + } + // Kernel package may be isntalled multiple versions. + // From the viewpoint of vulnerability detection, + // pay attention only to the running kernel + if pack.Name == "kernel" { + ver := fmt.Sprintf("%s-%s.%s", pack.Version, pack.Release, pack.Arch) + if o.Kernel.Release != ver { + o.log.Debugf("Not a running kernel: %s, uname: %s", ver, release) + continue + } else { + o.log.Debugf("Running kernel: %s, uname: %s", ver, release) + } + } + installed[pack.Name] = pack + } + } + return installed, nil } func (o *redhat) parseInstalledPackagesLine(line string) (models.Package, error) { diff --git a/scan/redhat_test.go b/scan/redhat_test.go index 2ee03ce1..9b59f1a4 100644 --- a/scan/redhat_test.go +++ b/scan/redhat_test.go @@ -667,14 +667,14 @@ python-ordereddict 0 1.1 3.el6ev installed bind-utils 30 9.3.6 25.P1.el5_11.8 updates pytalloc 0 2.0.7 2.el6 @CentOS 6.5/6.5` - r.setPackages(models.NewPackages( + r.Packages = models.NewPackages( models.Package{Name: "audit-libs"}, models.Package{Name: "bash"}, models.Package{Name: "python-libs"}, models.Package{Name: "python-ordereddict"}, models.Package{Name: "bind-utils"}, models.Package{Name: "pytalloc"}, - )) + ) var tests = []struct { in string out models.Packages diff --git a/scan/serverapi.go b/scan/serverapi.go index 71898e74..86c06cb5 100644 --- a/scan/serverapi.go +++ b/scan/serverapi.go @@ -63,14 +63,9 @@ type osPackages struct { // unsecure packages VulnInfos models.VulnInfos -} -func (p *osPackages) setPackages(pi models.Packages) { - p.Packages = pi -} - -func (p *osPackages) setVulnInfos(vi models.VulnInfos) { - p.VulnInfos = vi + // kernel information + Kernel models.Kernel } func detectOS(c config.ServerInfo) (osType osTypeInterface) {