Skip to content

Commit

Permalink
[WIP]Use repoquery for no sudo and avoid unintended line feed of yum …
Browse files Browse the repository at this point in the history
…or rpm. #444
  • Loading branch information
kotakanbe committed Jul 12, 2017
1 parent 98ab9db commit 977fd97
Show file tree
Hide file tree
Showing 8 changed files with 432 additions and 762 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
language: go

go:
- 1.7
- 1.8

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,12 +803,12 @@ In order to scan, the following dependencies are required, so you need to instal
|:-------------|-------------------:|:-------------|
| Ubuntu | 12, 14, 16| - |
| Debian | 7, 8| aptitude |
| CentOS | 6, 7| yum-plugin-changelog |
| Amazon | All | - |
| RHEL | 5 | yum-security |
| RHEL | 6, 7 | - |
| Oracle Linux | 5 | yum-security |
| Oracle Linux | 6, 7 | - |
| CentOS | 6, 7| yum-plugin-changelog, yum-utils |
| Amazon | All | - | TODO yum-utils?, yum-plugin-changelog
| RHEL | 5 | yum-security | TODO yum-utils?
| RHEL | 6, 7 | - | TODO yum-utils?
| Oracle Linux | 5 | yum-security | TODO yum-utils?
| Oracle Linux | 6, 7 | - |TODO yum-utils?
| FreeBSD | 10 | - |
| Raspbian | Wheezy, Jessie | - |
Expand Down
1 change: 1 addition & 0 deletions commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func (*ScanCmd) Usage() string {
[-cachedb-path=/path/to/cache.db]
[-ssh-native-insecure]
[-containers-only]
[-package-list-only]
[-skip-broken]
[-http-proxy=http://192.168.0.1:8080]
[-ask-key-password]
Expand Down
3 changes: 2 additions & 1 deletion models/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (ps Packages) MergeNewVersion(as Packages) {
if pack, ok := ps[a.Name]; ok {
pack.NewVersion = a.NewVersion
pack.NewRelease = a.NewRelease
pack.Repository = a.Repository
ps[a.Name] = pack
}
}
Expand Down Expand Up @@ -145,7 +146,7 @@ func (p Package) FormatChangelog() string {
}

// Changelog has contents of changelog and how to get it.
// Method: modesl.detectionMethodStr
// Method: models.detectionMethodStr
type Changelog struct {
Contents string
Method string
Expand Down
3 changes: 2 additions & 1 deletion models/vulninfos.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (
"github.com/future-architect/vuls/config"
)

// VulnInfos is VulnInfo list, getter/setter, sortable methods.
// VulnInfos has a map of VulnInfo
// Key: CveID
type VulnInfos map[string]VulnInfo

// Find elements that matches the function passed in argument
Expand Down
56 changes: 29 additions & 27 deletions scan/debian.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (o *debian) checkDependencies() error {
}

func (o *debian) scanPackages() error {
installed, upgradable, err := o.scanInstalledPackages()
installed, updatable, err := o.scanInstalledPackages()
if err != nil {
o.log.Errorf("Failed to scan installed packages")
return err
Expand All @@ -178,7 +178,7 @@ func (o *debian) scanPackages() error {
return nil
}

unsecure, err := o.scanUnsecurePackages(upgradable)
unsecure, err := o.scanUnsecurePackages(updatable)
if err != nil {
o.log.Errorf("Failed to scan vulnerable packages")
return err
Expand All @@ -189,7 +189,7 @@ func (o *debian) scanPackages() error {

func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, error) {
installed := models.Packages{}
upgradable := models.Packages{}
updatable := models.Packages{}

r := o.exec("dpkg-query -W", noSudo)
if !r.isSuccess() {
Expand All @@ -214,27 +214,27 @@ func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, erro
}
}

upgradableNames, err := o.GetUpgradablePackNames()
updatableNames, err := o.getUpdatablePackNames()
if err != nil {
return nil, nil, err
}
for _, name := range upgradableNames {
for _, name := range updatableNames {
for _, pack := range installed {
if pack.Name == name {
upgradable[name] = pack
updatable[name] = pack
break
}
}
}

// Fill the candidate versions of upgradable packages
err = o.fillCandidateVersion(upgradable)
err = o.fillCandidateVersion(updatable)
if err != nil {
return nil, nil, fmt.Errorf("Failed to fill candidate versions. err: %s", err)
}
installed.MergeNewVersion(upgradable)
installed.MergeNewVersion(updatable)

return installed, upgradable, nil
return installed, updatable, nil
}

var packageLinePattern = regexp.MustCompile(`^([^\t']+)\t(.+)$`)
Expand Down Expand Up @@ -263,14 +263,14 @@ func (o *debian) aptGetUpdate() error {
return nil
}

func (o *debian) scanUnsecurePackages(upgradable models.Packages) (models.VulnInfos, error) {
func (o *debian) scanUnsecurePackages(updatable models.Packages) (models.VulnInfos, error) {
o.aptGetUpdate()

// Setup changelog cache
current := cache.Meta{
Name: o.getServerInfo().GetServerName(),
Distro: o.getServerInfo().Distro,
Packs: upgradable,
Packs: updatable,
}

o.log.Debugf("Ensure changelog cache: %s", current.Name)
Expand All @@ -280,7 +280,7 @@ func (o *debian) scanUnsecurePackages(upgradable models.Packages) (models.VulnIn
}

// Collect CVE information of upgradable packages
vulnInfos, err := o.scanVulnInfos(upgradable, meta)
vulnInfos, err := o.scanVulnInfos(updatable, meta)
if err != nil {
return nil, fmt.Errorf("Failed to scan unsecure packages. err: %s", err)
}
Expand Down Expand Up @@ -344,12 +344,13 @@ func (o *debian) fillCandidateVersion(packages models.Packages) (err error) {
return fmt.Errorf("Not found: %s", k)
}
pack.NewVersion = ver.Candidate
//TODO Repository
packages[k] = pack
}
return
}

func (o *debian) GetUpgradablePackNames() (packNames []string, err error) {
func (o *debian) getUpdatablePackNames() (packNames []string, err error) {
cmd := util.PrependProxyEnv("LANGUAGE=en_US.UTF-8 apt-get upgrade --dry-run")
r := o.exec(cmd, noSudo)
if r.isSuccess(0, 1) {
Expand All @@ -360,7 +361,7 @@ func (o *debian) GetUpgradablePackNames() (packNames []string, err error) {
cmd, r.ExitStatus, r.Stdout, r.Stderr)
}

func (o *debian) parseAptGetUpgrade(stdout string) (upgradableNames []string, err error) {
func (o *debian) parseAptGetUpgrade(stdout string) (updatableNames []string, err error) {
startRe := regexp.MustCompile(`The following packages will be upgraded:`)
stopRe := regexp.MustCompile(`^(\d+) upgraded.*`)
startLineFound, stopLineFound := false, false
Expand All @@ -375,21 +376,21 @@ func (o *debian) parseAptGetUpgrade(stdout string) (upgradableNames []string, er
}
result := stopRe.FindStringSubmatch(line)
if len(result) == 2 {
numUpgradablePacks, err := strconv.Atoi(result[1])
nUpdatable, err := strconv.Atoi(result[1])
if err != nil {
return nil, fmt.Errorf(
"Failed to scan upgradable packages number. line: %s", line)
}
if numUpgradablePacks != len(upgradableNames) {
if nUpdatable != len(updatableNames) {
return nil, fmt.Errorf(
"Failed to scan upgradable packages, expected: %s, detected: %d",
result[1], len(upgradableNames))
result[1], len(updatableNames))
}
stopLineFound = true
o.log.Debugf("Found the stop line. line: %s", line)
break
}
upgradableNames = append(upgradableNames, strings.Fields(line)...)
updatableNames = append(updatableNames, strings.Fields(line)...)
}
if !startLineFound {
// no upgrades
Expand All @@ -410,28 +411,28 @@ type DetectedCveID struct {
Confidence models.Confidence
}

func (o *debian) scanVulnInfos(upgradablePacks models.Packages, meta *cache.Meta) (models.VulnInfos, error) {
func (o *debian) scanVulnInfos(updatablePacks models.Packages, meta *cache.Meta) (models.VulnInfos, error) {
type response struct {
pack *models.Package
DetectedCveIDs []DetectedCveID
}
resChan := make(chan response, len(upgradablePacks))
errChan := make(chan error, len(upgradablePacks))
reqChan := make(chan models.Package, len(upgradablePacks))
resChan := make(chan response, len(updatablePacks))
errChan := make(chan error, len(updatablePacks))
reqChan := make(chan models.Package, len(updatablePacks))
defer close(resChan)
defer close(errChan)
defer close(reqChan)

go func() {
for _, pack := range upgradablePacks {
for _, pack := range updatablePacks {
reqChan <- pack
}
}()

timeout := time.After(30 * 60 * time.Second)
concurrency := 10
tasks := util.GenWorkers(concurrency)
for range upgradablePacks {
for range updatablePacks {
tasks <- func() {
select {
case pack := <-reqChan:
Expand Down Expand Up @@ -459,7 +460,7 @@ func (o *debian) scanVulnInfos(upgradablePacks models.Packages, meta *cache.Meta
// { DetectedCveID{} : [package] }
cvePackages := make(map[DetectedCveID][]string)
errs := []error{}
for i := 0; i < len(upgradablePacks); i++ {
for i := 0; i < len(updatablePacks); i++ {
select {
case response := <-resChan:
o.Packages[response.pack.Name] = *response.pack
Expand All @@ -474,7 +475,7 @@ func (o *debian) scanVulnInfos(upgradablePacks models.Packages, meta *cache.Meta
cvePackages[cve] = packNames
}
o.log.Infof("(%d/%d) Scanned %s: %s",
i+1, len(upgradablePacks), response.pack.Name, cves)
i+1, len(updatablePacks), response.pack.Name, cves)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
Expand All @@ -500,7 +501,7 @@ func (o *debian) scanVulnInfos(upgradablePacks models.Packages, meta *cache.Meta
}

// Update meta package information of changelog cache to the latest one.
meta.Packs = upgradablePacks
meta.Packs = updatablePacks
if err := cache.DB.RefreshMeta(*meta); err != nil {
return nil, err
}
Expand Down Expand Up @@ -630,6 +631,7 @@ func (o *debian) getCveIDsFromChangelog(
return []DetectedCveID{}, &pack
}

//TODO move to scann.go
var cveRe = regexp.MustCompile(`(CVE-\d{4}-\d{4,})`)

// Collect CVE-IDs included in the changelog.
Expand Down
Loading

0 comments on commit 977fd97

Please sign in to comment.