Compare commits

..

13 Commits

Author SHA1 Message Date
Kota Kanbe
169db6e320 sort 2021-11-08 12:29:15 +09:00
Kota Kanbe
79c7fc972c reverse deps recursively 2021-11-05 10:01:18 +09:00
Kota Kanbe
fb9cebd3e2 feat reversedeps 2021-11-04 10:47:19 +09:00
Kota Kanbe
43d987e200 feat(scan) detect the dependencies for each updatable packages 2021-11-01 12:45:09 +09:00
sadayuki-matsuno
ffdb78962f update dictionaries (#1326) 2021-10-29 11:24:49 +09:00
Kota Kanbe
321dae37ce chore: update readme 2021-10-24 17:38:57 +09:00
Kota Kanbe
a31797af0b Merge branch 'sakura' 2021-10-24 17:33:48 +09:00
Kota Kanbe
32999cf432 chore: udpate readme 2021-10-24 17:32:35 +09:00
Kota Kanbe
88218f5d92 chore: update sponsor (#1325) 2021-10-24 17:25:03 +09:00
Kota Kanbe
15761933ac chore: update sponsor 2021-10-24 17:01:35 +09:00
Kota Kanbe
0b62842f0e chore: fix go-sqlite3 deps (#1324) 2021-10-20 12:33:59 +09:00
Kota Kanbe
6bceddeeda chore: update goval-dictionary (#1323)
* chore: update goval-dictionary

* fix errs
2021-10-20 11:10:33 +09:00
Kota Kanbe
2dcbff8cd5 chore: sponsor (#1321)
* fix readme

* chore: fix lint
2021-10-17 16:41:51 +09:00
18 changed files with 517 additions and 76 deletions

View File

@@ -186,11 +186,14 @@ see [vulsdoc](https://vuls.io/docs/en/how-to-contribute.html)
----
## Stargazers over time
## Sponsors
[![Stargazers over time](https://starcharts.herokuapp.com/future-architect/vuls.svg)](https://starcharts.herokuapp.com/future-architect/vuls)
| | |
| ------------- | ------------- |
| <a href="https://www.tines.com/?utm_source=oss&utm_medium=sponsorship&utm_campaign=vuls"><img src="img/sponsor/tines.png" align="left" width="600px" ></a> | Tines is no-code automation for security teams. Build powerful, reliable workflows without a development team. |
| <a href="https://www.sakura.ad.jp/"><img src="https://vuls.io/img/icons/sakura.svg" align="left" width="600px" ></a> | SAKURA internet Inc. is an Internet company founded in 1996. We provide cloud computing services such as "Sakura's Shared Server", "Sakura's VPS", and "Sakura's Cloud" to meet the needs of a wide range of customers, from individuals and corporations to the education and public sectors, using its own data centers in Japan. Based on the philosophy of "changing what you want to do into what you can do," we offer DX solutions for all fields. |
-----;
----
## License

View File

@@ -216,7 +216,7 @@ func newCveDB(cnf config.VulnDictInterface) (driver cvedb.DB, locked bool, err e
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
driver, locked, err = cvedb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL())
driver, locked, err = cvedb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), cvedb.Option{})
if err != nil {
err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path)
return nil, locked, err

View File

@@ -150,12 +150,12 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
if 0 < config.Conf.CvssScoreOver {
r.ScannedCves, nFiltered = r.ScannedCves.FilterByCvssOver(config.Conf.CvssScoreOver)
logging.Log.Infof("%s: %d CVEs filtered by --cvss-over=%d", r.FormatServerName(), nFiltered, config.Conf.CvssScoreOver)
logging.Log.Infof("%s: %d CVEs filtered by --cvss-over=%g", r.FormatServerName(), nFiltered, config.Conf.CvssScoreOver)
}
if config.Conf.IgnoreUnfixed {
r.ScannedCves, nFiltered = r.ScannedCves.FilterUnfixed(config.Conf.IgnoreUnfixed)
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unfixed=%d", r.FormatServerName(), nFiltered)
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unfixed", r.FormatServerName(), nFiltered)
}
if 0 < config.Conf.ConfidenceScoreOver {
@@ -190,7 +190,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
// IgnoreUnscored
if config.Conf.IgnoreUnscoredCves {
r.ScannedCves, nFiltered = r.ScannedCves.FindScoredVulns()
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unscored-cves=%s", r.FormatServerName(), nFiltered, config.Conf.IgnoreUnscoredCves)
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unscored-cves", r.FormatServerName(), nFiltered)
}
r.FilterInactiveWordPressLibs(config.Conf.WpScan.DetectInactive)

View File

@@ -211,7 +211,7 @@ func newExploitDB(cnf config.VulnDictInterface) (driver exploitdb.DB, locked boo
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = exploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
if driver, locked, err = exploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), exploitdb.Option{}); err != nil {
if locked {
return nil, true, xerrors.Errorf("exploitDB is locked. err: %w", err)
}

View File

@@ -207,7 +207,7 @@ func newMetasploitDB(cnf config.VulnDictInterface) (driver metasploitdb.DB, lock
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), metasploitdb.Option{}); err != nil {
if locked {
return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err)
}

19
go.mod
View File

@@ -16,7 +16,7 @@ require (
github.com/briandowns/spinner v1.16.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
github.com/cheggaaa/pb v1.0.27
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.14.0
@@ -51,13 +51,13 @@ require (
github.com/spf13/afero v1.6.0
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211013020338-ec22aa70ffdb
github.com/vulsio/go-exploitdb v0.4.2-0.20210930235136-c10d2716b7e2
github.com/vulsio/go-msfdb v0.2.1-0.20210928020521-9b56a938f544
github.com/vulsio/gost v0.4.1-0.20210928234623-3e6372ba2821
github.com/vulsio/goval-dictionary v0.6.1
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211028094424-0a854f8e8f85
github.com/vulsio/go-exploitdb v0.4.2-0.20211028071949-1ebf9c4f6c4d
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8
github.com/vulsio/goval-dictionary v0.6.1-0.20211028072035-e85e14b91ccc
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 // indirect
golang.org/x/net v0.0.0-20211019232329-c6ed85c7a12d // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7 // indirect
@@ -87,6 +87,7 @@ require (
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/caarlos0/env/v6 v6.0.0 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
@@ -123,7 +124,7 @@ require (
github.com/magiconair/properties v1.8.5 // indirect
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
@@ -142,7 +143,7 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect

33
go.sum
View File

@@ -1118,7 +1118,6 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
@@ -1180,8 +1179,8 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -1610,16 +1609,16 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211013020338-ec22aa70ffdb h1:HTgus8EIfZiTvNTKd7JHZH+hwshKYXwCVoNMdmVi38M=
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211013020338-ec22aa70ffdb/go.mod h1:Ii9TEH35giMSWJM2FwGm1PCPxuBKrbaYhDun2PM7ERo=
github.com/vulsio/go-exploitdb v0.4.2-0.20210930235136-c10d2716b7e2 h1:9qNocUoE2Ko2LJFWDIuDZOuo4KHMxksIpAWY3BAOCjM=
github.com/vulsio/go-exploitdb v0.4.2-0.20210930235136-c10d2716b7e2/go.mod h1:C1X/lRIvDDBWDeW19Msw7asZ4q0pFjmFx/kXGns2raA=
github.com/vulsio/go-msfdb v0.2.1-0.20210928020521-9b56a938f544 h1:wG6rTODeLpm+N8wERjdVTo5kr64WqNEDR+VrKny/vAo=
github.com/vulsio/go-msfdb v0.2.1-0.20210928020521-9b56a938f544/go.mod h1:QsHhtjF4hAheLgeGJQRv/ccmE3txtOSgwzTgziyStKY=
github.com/vulsio/gost v0.4.1-0.20210928234623-3e6372ba2821 h1:MPbc8QNX9Rld5ksdWTWMdKbxfgj4qhiXosEvwfRl9Jk=
github.com/vulsio/gost v0.4.1-0.20210928234623-3e6372ba2821/go.mod h1:49trASwbe0ZhntJhEc1rv3MDGUpIhIkZktELgZ8a5YA=
github.com/vulsio/goval-dictionary v0.6.1 h1:w2AXwgPWD5/IrJ+44ywD0u5I9ILNdHvzlR+n6iu0eAQ=
github.com/vulsio/goval-dictionary v0.6.1/go.mod h1:RU1jWunEAwnErgIbM5Hc2j4OnTHQEvMagBq6/6wfWPU=
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211028094424-0a854f8e8f85 h1:nEhaBIAixxDQGeu/3sgHLSjpQpKGqENcUtWHEwkwC4k=
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211028094424-0a854f8e8f85/go.mod h1:Ii9TEH35giMSWJM2FwGm1PCPxuBKrbaYhDun2PM7ERo=
github.com/vulsio/go-exploitdb v0.4.2-0.20211028071949-1ebf9c4f6c4d h1:iMXVmz2f1Phor1TAmRKx324mDOuXst0GXGEboVRgysg=
github.com/vulsio/go-exploitdb v0.4.2-0.20211028071949-1ebf9c4f6c4d/go.mod h1:2R5gwySHHjF3DoEt11xqnIWEJLS93CLfCUDPwYH+VdM=
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14 h1:2uYZw2gQ0kymwerTS1FXZbNgptnlye+SB7o3QlLDIBo=
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14/go.mod h1:NGdcwWxCK/ES8vZ/crzREqI69S5gH1MivCpSp1pa2Rc=
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8 h1:jqsECpLRp1EAXGOdhPxHzqYjWP5l980GjJ8s/AUYH/4=
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8/go.mod h1:DaWLus8dJ4DdhVsBe5TAEEZ3IdoTMIb/z2StR4Bhb7Q=
github.com/vulsio/goval-dictionary v0.6.1-0.20211028072035-e85e14b91ccc h1:YwPr8QCkg8d6ezmbo6P28dDyRtfbqbHpG6Q2i0I/rA0=
github.com/vulsio/goval-dictionary v0.6.1-0.20211028072035-e85e14b91ccc/go.mod h1:drWHfa4y/l/GwiXJzNLTJSzugcI4O7SxdxFFxyuox1o=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
@@ -1858,8 +1857,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 h1:qOfNqBm5gk93LjGZo1MJaKY6Bph39zOKz1Hz2ogHj1w=
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211019232329-c6ed85c7a12d h1:HQcdyB13Mr2DxEMfcsz71PHjYBVFpb6W3aCYFv+cDdk=
golang.org/x/net v0.0.0-20211019232329-c6ed85c7a12d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -2014,8 +2013,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=

View File

@@ -88,7 +88,7 @@ func newGostDB(cnf config.GostConf) (driver db.DB, locked bool, err error) {
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
if driver, locked, err = db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), db.Option{}); err != nil {
if locked {
return nil, true, xerrors.Errorf("gostDB is locked. err: %w", err)
}

BIN
img/sponsor/tines.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -72,6 +72,31 @@ func (ps Packages) FindByFQPN(nameVerRel string) (*Package, error) {
return nil, xerrors.Errorf("Failed to find the package: %s", nameVerRel)
}
// ResolveReverseDepsRecursively resolve and set reverse dependencies for each packages recursively
func (ps Packages) ResolveReverseDepsRecursively() {
for name, pkg := range ps {
depsmap := ps.resolveReverseDeps(pkg, map[string]struct{}{})
delete(depsmap, pkg.Name)
for depname := range depsmap {
pkg.ReverseDependenciesRecursively = append(pkg.ReverseDependenciesRecursively, depname)
}
ps[name] = pkg
}
}
func (ps Packages) resolveReverseDeps(pkg Package, acc map[string]struct{}) map[string]struct{} {
acc[pkg.Name] = struct{}{}
for _, name := range pkg.ReverseDependencies {
if _, ok := acc[name]; ok {
continue
}
if p, ok := ps[name]; ok {
acc = ps.resolveReverseDeps(p, acc)
}
}
return acc
}
// Package has installed binary packages.
type Package struct {
Name string `json:"name"`
@@ -84,6 +109,18 @@ type Package struct {
Changelog *Changelog `json:"changelog,omitempty"`
AffectedProcs []AffectedProcess `json:",omitempty"`
NeedRestartProcs []NeedRestartProcess `json:",omitempty"`
// Dependencies are dependent packages
Dependencies []string `json:",omitempty"`
// ReverseDependencies are packages which depend on this package
ReverseDependencies []string `json:",omitempty"`
// ReverseDependencies are packages which depend on this package
ReverseDependenciesRecursively []string `json:",omitempty"`
// DependenciesForUpdate are packages that needs to be updated together
DependenciesForUpdate []string `json:",omitempty"`
}
// FQPN returns Fully-Qualified-Package-Name

View File

@@ -428,3 +428,166 @@ func Test_NewPortStat(t *testing.T) {
})
}
}
func TestPackages_resolveReverseDeps(t *testing.T) {
type args struct {
pkg Package
acc map[string]struct{}
}
tests := []struct {
name string
ps Packages
args args
want map[string]struct{}
}{
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
args: args{
pkg: Package{
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
acc: map[string]struct{}{},
},
want: map[string]struct{}{
"pkgA": {},
"pkgB": {},
"pkgC": {},
},
},
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
},
},
args: args{
pkg: Package{
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
acc: map[string]struct{}{},
},
want: map[string]struct{}{
"pkgA": {},
"pkgB": {},
"pkgC": {},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.ps.resolveReverseDeps(tt.args.pkg, tt.args.acc); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Packages.resolveReverseDeps() = %v, want %v", got, tt.want)
}
})
}
}
func TestPackages_resolveReverseDepsRecursively(t *testing.T) {
tests := []struct {
name string
ps Packages
want Packages
}{
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
want: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgB", "pkgC"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgC"},
ReverseDependenciesRecursively: []string{"pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{""},
},
},
},
{
name: "",
ps: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
},
},
want: map[string]Package{
"pkgA": {
Name: "pkgA",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgB", "pkgC"},
},
"pkgB": {
Name: "pkgB",
ReverseDependencies: []string{"pkgA", "pkgC"},
ReverseDependenciesRecursively: []string{"pkgA", "pkgC"},
},
"pkgC": {
Name: "pkgC",
ReverseDependencies: []string{"pkgB"},
ReverseDependenciesRecursively: []string{"pkgA", "pkgB"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.ps.ResolveReverseDepsRecursively()
if !reflect.DeepEqual(tt.ps, tt.want) {
t.Errorf("Packages.resolveReverseDepsRecursively() = \n%+v, want \n%+v", tt.ps, tt.want)
}
})
}
}

View File

@@ -33,7 +33,7 @@ func (o Alpine) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}

View File

@@ -158,7 +158,7 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
@@ -472,7 +472,7 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}

View File

@@ -36,7 +36,7 @@ func (b Base) CheckIfOvalFetched(osFamily, release string) (fetched bool, err er
return false, err
}
if !b.Cnf.IsFetchViaHTTP() {
driver, err := newOvalDB(b.Cnf, ovalFamily)
driver, err := newOvalDB(b.Cnf)
if err != nil {
return false, err
}
@@ -75,7 +75,7 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
}
var lastModified time.Time
if !b.Cnf.IsFetchViaHTTP() {
driver, err := newOvalDB(b.Cnf, ovalFamily)
driver, err := newOvalDB(b.Cnf)
if err != nil {
return false, err
}
@@ -112,7 +112,7 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
}
// NewOvalDB returns oval db client
func newOvalDB(cnf config.VulnDictInterface, familyInScanResult string) (driver db.DB, err error) {
func newOvalDB(cnf config.VulnDictInterface) (driver db.DB, err error) {
if cnf.IsFetchViaHTTP() {
return nil, nil
}
@@ -122,12 +122,7 @@ func newOvalDB(cnf config.VulnDictInterface, familyInScanResult string) (driver
path = cnf.GetSQLite3Path()
}
ovalFamily, err := GetFamilyInOval(familyInScanResult)
if err != nil {
return nil, err
}
driver, locked, err := db.NewDB(ovalFamily, cnf.GetType(), path, cnf.GetDebugSQL())
driver, locked, err := db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), db.Option{})
if err != nil {
if locked {
err = xerrors.Errorf("SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)

View File

@@ -28,7 +28,7 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}

View File

@@ -35,7 +35,7 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}

View File

@@ -4,8 +4,10 @@ import (
"bufio"
"fmt"
"regexp"
"sort"
"strings"
"github.com/cheggaaa/pb"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
@@ -218,6 +220,10 @@ func (o *redhatBase) execCheckDeps(packNames []string) error {
return nil
}
func (o *redhatBase) isDnf() bool {
return o.exec(util.PrependProxyEnv(`repoquery --version | grep dnf`), o.sudo.repoquery()).isSuccess()
}
func (o *redhatBase) preCure() error {
if err := o.detectIPAddr(); err != nil {
o.log.Warnf("Failed to detect IP addresses: %s", err)
@@ -230,8 +236,7 @@ func (o *redhatBase) preCure() error {
func (o *redhatBase) postScan() error {
if o.isExecYumPS() {
if err := o.pkgPs(o.getOwnerPkgs); err != nil {
err = xerrors.Errorf("Failed to execute yum-ps: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to execute yum-ps: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -239,8 +244,7 @@ func (o *redhatBase) postScan() error {
if o.isExecNeedsRestarting() {
if err := o.needsRestarting(); err != nil {
err = xerrors.Errorf("Failed to execute need-restarting: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to execute need-restarting: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -260,15 +264,10 @@ func (o *redhatBase) scanPackages() (err error) {
return xerrors.Errorf("Failed to scan installed packages: %w", err)
}
if o.EnabledDnfModules, err = o.detectEnabledDnfModules(); err != nil {
return xerrors.Errorf("Failed to detect installed dnf modules: %w", err)
}
fn := func(pkgName string) execResult { return o.exec(fmt.Sprintf("rpm -q --last %s", pkgName), noSudo) }
o.Kernel.RebootRequired, err = o.rebootRequired(fn)
if err != nil {
err = xerrors.Errorf("Failed to detect the kernel reboot required: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to detect the kernel reboot required: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
}
@@ -281,15 +280,31 @@ func (o *redhatBase) scanPackages() (err error) {
}
}
if err := o.yumMakeCache(); err != nil {
return xerrors.Errorf("Failed to `yum makecache`: %w", err)
}
// `dnf module list` needs yum cache
if o.EnabledDnfModules, err = o.detectEnabledDnfModules(); err != nil {
return xerrors.Errorf("Failed to detect installed dnf modules: %w", err)
}
updatable, err := o.scanUpdatablePackages()
if err != nil {
err = xerrors.Errorf("Failed to scan updatable packages: %w", err)
o.log.Warnf("err: %+v", err)
o.log.Warnf("err: %+v", xerrors.Errorf("Failed to scan updatable packages: %w", err))
o.warns = append(o.warns, err)
// Only warning this error
} else {
o.Packages.MergeNewVersion(updatable)
}
if o.getServerInfo().Mode.IsDeep() {
resolver := yumDependentResolver{redhat: o, isDnf: o.isDnf()}
resolver.detectDependenciesForUpdate()
resolver.detectReverseDependencies()
o.Packages.ResolveReverseDepsRecursively()
}
return nil
}
@@ -420,13 +435,8 @@ func (o *redhatBase) yumMakeCache() error {
}
func (o *redhatBase) scanUpdatablePackages() (models.Packages, error) {
if err := o.yumMakeCache(); err != nil {
return nil, xerrors.Errorf("Failed to `yum makecache`: %w", err)
}
isDnf := o.exec(util.PrependProxyEnv(`repoquery --version | grep dnf`), o.sudo.repoquery()).isSuccess()
cmd := `repoquery --all --pkgnarrow=updates --qf='%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{REPO}'`
if isDnf {
if o.isDnf() {
cmd = `repoquery --upgrades --qf='%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{REPONAME}' -q`
}
for _, repo := range o.getServerInfo().Enablerepo {
@@ -700,9 +710,6 @@ func (o *redhatBase) detectEnabledDnfModules() ([]string, error) {
cmd := `dnf --nogpgcheck --cacheonly --color=never --quiet module list --enabled`
r := o.exec(util.PrependProxyEnv(cmd), noSudo)
if !r.isSuccess() {
if strings.Contains(r.Stdout, "Cache-only enabled but no cache") {
return nil, xerrors.Errorf("sudo yum check-update to make local cache before scanning: %s", r)
}
return nil, xerrors.Errorf("Failed to dnf module list: %s", r)
}
return o.parseDnfModuleList(r.Stdout)
@@ -723,3 +730,122 @@ func (o *redhatBase) parseDnfModuleList(stdout string) (labels []string, err err
}
return
}
type yumDependentResolver struct {
redhat *redhatBase
isDnf bool
}
func (o *yumDependentResolver) detectDependenciesForUpdate() {
o.redhat.log.Infof("Detecting the dependencies for each packages when yum updating")
o.redhat.log.Infof("If it is too slow, `yum clean all` may make it faster")
bar := pb.StartNew(len(o.redhat.Packages))
for name, pkg := range o.redhat.Packages {
bar.Increment()
if pkg.Version == pkg.NewVersion && pkg.Release == pkg.NewRelease {
// only updatable pkgs
continue
}
names, err := o.scanUpdatablePkgDeps(name)
if err != nil {
o.redhat.log.Warnf("err: %+v", xerrors.Errorf("Failed to scan dependent packages for update: %w", err))
o.redhat.warns = append(o.redhat.warns, err)
// Only warning this error
}
sort.Strings(names)
pkg.DependenciesForUpdate = names
o.redhat.Packages[name] = pkg
}
bar.Finish()
return
}
func (o *yumDependentResolver) scanUpdatablePkgDeps(name string) (depsPkgNames []string, err error) {
cmd := fmt.Sprintf("LANGUAGE=en_US.UTF-8 yum install --assumeno --cacheonly %s", name)
r := o.redhat.exec(cmd, true)
if !r.isSuccess(0, 1) {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
names := o.parseYumInstall(r.Stdout)
for _, n := range names {
if _, ok := o.redhat.Packages[n]; ok {
depsPkgNames = append(depsPkgNames, n)
}
}
return
}
func (o *yumDependentResolver) parseYumInstall(stdout string) []string {
names, inDepsLines := []string{}, false
scanner := bufio.NewScanner(strings.NewReader(stdout))
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "Updating for dependencies:") {
inDepsLines = true
continue
}
if inDepsLines {
ss := strings.Fields(line)
if len(ss) == 0 {
break
}
names = append(names, ss[0])
}
}
return names
}
func (o *yumDependentResolver) detectReverseDependencies() {
o.redhat.log.Infof("Detecting the reverse dependencies for each packages")
bar := pb.StartNew(len(o.redhat.Packages))
for name, pkg := range o.redhat.Packages {
bar.Increment()
// if pkg.Version == pkg.NewVersion && pkg.Release == pkg.NewRelease {
// continue
// }
names, err := o.repoqueryWhatRequires(name)
if err != nil {
o.redhat.log.Warnf("err: %+v", xerrors.Errorf("Failed to scan reverse dependent packages: %w", err))
o.redhat.warns = append(o.redhat.warns, err)
// Only warning this error
}
sort.Strings(names)
pkg.ReverseDependencies = names
o.redhat.Packages[name] = pkg
}
bar.Finish()
return
}
func (o *yumDependentResolver) repoqueryWhatRequires(pkgName string) (depsPkgNames []string, err error) {
cmd := `LANGUAGE=en_US.UTF-8 repoquery --cache --resolve --pkgnarrow=installed --qf "%{name}" --whatrequires ` + pkgName
if o.isDnf {
cmd = `LANGUAGE=en_US.UTF-8 repoquery --cache --installed --qf "%{name}" --whatrequires ` + pkgName
}
r := o.redhat.exec(cmd, true)
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
names := o.parseRepoqueryWhatRequires(r.Stdout)
for _, n := range names {
if pkgName == n {
continue
}
if _, ok := o.redhat.Packages[n]; ok {
depsPkgNames = append(depsPkgNames, n)
}
}
return
}
func (o *yumDependentResolver) parseRepoqueryWhatRequires(stdout string) []string {
names := []string{}
scanner := bufio.NewScanner(strings.NewReader(stdout))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line != "" {
names = append(names, line)
}
}
return names
}

View File

@@ -10,11 +10,6 @@ import (
"github.com/k0kubun/pp"
)
// func unixtimeNoerr(s string) time.Time {
// t, _ := unixtime(s)
// return t
// }
func TestParseInstalledPackagesLinesRedhat(t *testing.T) {
r := newRHEL(config.ServerInfo{})
r.Distro = config.Distro{Family: constant.RedHat}
@@ -641,3 +636,125 @@ kernel-3.10.0-1062.12.1.el7.x86_64 Sat 29 Feb 2020 12:09:00 PM UTC`,
})
}
}
func Test_redhatBase_parseYumInstall(t *testing.T) {
type fields struct {
base base
sudo rootPriv
}
type args struct {
stdout string
}
tests := []struct {
name string
fields fields
args args
wantPkgNames []string
}{
{
name: "ok",
fields: fields{
base: base{},
},
args: args{
stdout: `===========================================================================================================================================================
Package Arch Version Repository Size
===========================================================================================================================================================
Updating:
glibc x86_64 2.17-325.el7_9 updates 3.6 M
Updating for dependencies:
glibc-common x86_64 2.17-325.el7_9 updates 12 M
glibc-devel x86_64 2.17-325.el7_9 updates 1.1 M
glibc-headers x86_64 2.17-325.el7_9 updates 691 k
Transaction Summary
===========================================================================================================================================================
Upgrade 1 Package (+3 Dependent packages)
Exiting on user command
Your transaction was saved, rerun it with:
yum load-transaction /tmp/yum_save_tx.2021-10-25.08-24.1EXcRc.yumtx`,
},
wantPkgNames: []string{
"glibc-common",
"glibc-devel",
"glibc-headers",
},
},
{
name: "no deps",
fields: fields{
base: base{},
},
args: args{
stdout: `Package zlib-1.2.7-19.el7_9.x86_64 already installed and latest version`,
},
wantPkgNames: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &redhatBase{
base: tt.fields.base,
}
resolver := yumDependentResolver{redhat: o}
if gotPkgNames := resolver.parseYumInstall(tt.args.stdout); !reflect.DeepEqual(gotPkgNames, tt.wantPkgNames) {
t.Errorf("redhatBase.parseYumInstall() = %v, want %v", gotPkgNames, tt.wantPkgNames)
}
})
}
}
func Test_yumDependentResolver_parseRepoqueryWhatRequires(t *testing.T) {
type fields struct {
redhat *redhatBase
}
type args struct {
stdout string
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "no deps",
fields: fields{redhat: &redhatBase{}},
args: args{
stdout: "",
},
want: []string{},
},
{
name: "no deps",
fields: fields{redhat: &redhatBase{}},
args: args{
stdout: `which
whois
wpa_supplicant
xcb-util
xfsprogs
xinetd`,
},
want: []string{
"which",
"whois",
"wpa_supplicant",
"xcb-util",
"xfsprogs",
"xinetd",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &yumDependentResolver{
redhat: tt.fields.redhat,
}
if got := o.parseRepoqueryWhatRequires(tt.args.stdout); !reflect.DeepEqual(got, tt.want) {
t.Errorf("yumDependentResolver.parseRepoqueryWhatRequires() = %v, want %v", got, tt.want)
}
})
}
}