@@ -36,66 +36,82 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
3636 return nil , xerrors .Errorf ("Failed to fill with Library dependency: %w" , err )
3737 }
3838
39- if err := DetectPkgCves (& r , config .Conf .Vuls2 , config .Conf .NoProgress ); err != nil {
40- return nil , xerrors .Errorf ("Failed to detect Pkg CVE: %w" , err )
41- }
39+ // One vuls2 db session for this server's package/CPE detection and the
40+ // enrichment that follows: detection warms the read cache and
41+ // enrichment, querying the same CVEs, reuses it instead of opening and
42+ // rebuilding a fresh cache. The session opens lazily on the first path
43+ // that queries the db (as the unshared code did), and is closed at the
44+ // end of this server's turn so each server holds the db only while it
45+ // needs it.
46+ if err := func () error {
47+ sesh := vuls2 .NewSession (config .Conf .Vuls2 , config .Conf .NoProgress )
48+ defer sesh .Close ()
49+
50+ if err := DetectPkgCves (& r , sesh ); err != nil {
51+ return xerrors .Errorf ("Failed to detect Pkg CVE: %w" , err )
52+ }
4253
43- // Collect the user-supplied CPE URIs to check. Sources, in order:
44- // 1. r.Config.Scan.Servers[...].CpeNames — the per-server CPE list
45- // that was captured at scan time and shipped in the result JSON.
46- // Using the scan-time snapshot keeps detection coupled to the
47- // server that was actually scanned, and lets detection run
48- // without re-loading config.toml.
49- // 2. OWASP DC XML, if configured.
50- //
51- // Synthesised Apple CPEs for macOS scans are detected separately in
52- // DetectPkgCves (macOS has no package security database).
53- // Prefer the scan-time snapshot; results produced by an older Vuls
54- // (or an external producer) may not embed config.scan.servers, so
55- // fall back to the report-time config.Conf.Servers in that case to
56- // keep CPE detection working for such inputs.
57- serverInfo , serverFound := r .Config .Scan .Servers [r .ServerName ]
58- if ! serverFound {
59- serverInfo , serverFound = config .Conf .Servers [r .ServerName ]
60- }
61- cpeURIs , owaspDCXMLPath := []string {}, ""
62- cpes := []vuls2.CPE {}
63- if serverFound {
64- if len (r .Container .ContainerID ) == 0 {
65- cpeURIs = serverInfo .CpeNames
66- owaspDCXMLPath = serverInfo .OwaspDCXMLPath
67- } else {
68- if con , ok := serverInfo .Containers [r .Container .Name ]; ok {
69- cpeURIs = con .Cpes
70- owaspDCXMLPath = con .OwaspDCXMLPath
54+ // Collect the user-supplied CPE URIs to check. Sources, in order:
55+ // 1. r.Config.Scan.Servers[...].CpeNames — the per-server CPE list
56+ // that was captured at scan time and shipped in the result JSON.
57+ // Using the scan-time snapshot keeps detection coupled to the
58+ // server that was actually scanned, and lets detection run
59+ // without re-loading config.toml.
60+ // 2. OWASP DC XML, if configured.
61+ //
62+ // Synthesised Apple CPEs for macOS scans are detected separately in
63+ // DetectPkgCves (macOS has no package security database).
64+ // Prefer the scan-time snapshot; results produced by an older Vuls
65+ // (or an external producer) may not embed config.scan.servers, so
66+ // fall back to the report-time config.Conf.Servers in that case to
67+ // keep CPE detection working for such inputs.
68+ serverInfo , serverFound := r .Config .Scan .Servers [r .ServerName ]
69+ if ! serverFound {
70+ serverInfo , serverFound = config .Conf .Servers [r .ServerName ]
71+ }
72+ cpeURIs , owaspDCXMLPath := []string {}, ""
73+ cpes := []vuls2.CPE {}
74+ if serverFound {
75+ if len (r .Container .ContainerID ) == 0 {
76+ cpeURIs = serverInfo .CpeNames
77+ owaspDCXMLPath = serverInfo .OwaspDCXMLPath
78+ } else {
79+ if con , ok := serverInfo .Containers [r .Container .Name ]; ok {
80+ cpeURIs = con .Cpes
81+ owaspDCXMLPath = con .OwaspDCXMLPath
82+ }
7183 }
7284 }
73- }
74- if owaspDCXMLPath != "" {
75- owaspCPEs , err := parser .Parse (owaspDCXMLPath )
76- if err != nil {
77- return nil , xerrors .Errorf ("Failed to read OWASP Dependency Check XML on %s, `%s`, err: %w" ,
78- r .ServerInfo (), owaspDCXMLPath , err )
85+ if owaspDCXMLPath != "" {
86+ owaspCPEs , err := parser .Parse (owaspDCXMLPath )
87+ if err != nil {
88+ return xerrors .Errorf ("Failed to read OWASP Dependency Check XML on %s, `%s`, err: %w" ,
89+ r .ServerInfo (), owaspDCXMLPath , err )
90+ }
91+ cpeURIs = append (cpeURIs , owaspCPEs ... )
92+ }
93+ for _ , uri := range cpeURIs {
94+ cpes = append (cpes , vuls2.CPE {
95+ URI : uri ,
96+ UseJVN : true ,
97+ })
7998 }
80- cpeURIs = append (cpeURIs , owaspCPEs ... )
81- }
82- for _ , uri := range cpeURIs {
83- cpes = append (cpes , vuls2.CPE {
84- URI : uri ,
85- UseJVN : true ,
86- })
87- }
8899
89- if err := DetectCpeURIsCves (& r , cpes , config . Conf . Vuls2 , config . Conf . NoProgress ); err != nil {
90- return nil , xerrors .Errorf ("Failed to detect CVE of `%s`: %w" , cpeURIs , err )
91- }
100+ if err := DetectCpeURIsCves (& r , cpes , sesh ); err != nil {
101+ return xerrors .Errorf ("Failed to detect CVE of `%s`: %w" , cpeURIs , err )
102+ }
92103
93- if err := DetectWordPressCves (& r , config .Conf .WpScan ); err != nil {
94- return nil , xerrors .Errorf ("Failed to detect WordPress Cves: %w" , err )
95- }
104+ if err := DetectWordPressCves (& r , config .Conf .WpScan ); err != nil {
105+ return xerrors .Errorf ("Failed to detect WordPress Cves: %w" , err )
106+ }
96107
97- if err := vuls2 .EnrichVulnInfos (& r , config .Conf .Vuls2 , config .Conf .NoProgress ); err != nil {
98- return nil , xerrors .Errorf ("Failed to enrich vulnerability data with vuls2: %w" , err )
108+ if err := vuls2 .EnrichVulnInfos (& r , sesh ); err != nil {
109+ return xerrors .Errorf ("Failed to enrich vulnerability data with vuls2: %w" , err )
110+ }
111+
112+ return nil
113+ }(); err != nil {
114+ return nil , xerrors .Errorf ("Failed to detect CVEs of %s. err: %w" , r .FormatServerName (), err )
99115 }
100116
101117 r .ReportedBy , _ = os .Hostname ()
@@ -189,10 +205,14 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
189205// post-processing. macOS has no package security database, so its installed
190206// applications and OS are translated to Apple CPEs (vuls2.MacOSCPEs) and
191207// detected through the CPE path here. It keeps the master-era name and
192- // calling convention so library consumers that drive detection as
193- // DetectPkgCves -> DetectCpeURIsCves keep working; user-supplied CPE-URI
208+ // DetectPkgCves -> DetectCpeURIsCves driving order; user-supplied CPE-URI
194209// detection lives in DetectCpeURIsCves.
195- func DetectPkgCves (r * models.ScanResult , vuls2Conf config.Vuls2Conf , noProgress bool ) error {
210+ //
211+ // sesh is the vuls2 db session to query (see vuls2.Session), created with
212+ // vuls2.NewSession and owned (Closed) by the caller; it is shared with this
213+ // server's CPE detection and enrichment so all three reuse one warm db
214+ // connection.
215+ func DetectPkgCves (r * models.ScanResult , sesh * vuls2.Session ) error {
196216 switch r .Family {
197217 case constant .MacOSX , constant .MacOSXServer , constant .MacOS , constant .MacOSServer :
198218 // macOS has no package security database; the OS itself (when its release
@@ -205,14 +225,14 @@ func DetectPkgCves(r *models.ScanResult, vuls2Conf config.Vuls2Conf, noProgress
205225 case 0 :
206226 r .Errors = append (r .Errors , xerrors .Errorf ("Failed to detect CVE for %s: no OS release and no detectable applications" , r .Family ).Error ())
207227 default :
208- if err := vuls2 .DetectCPEs (r , cpes , vuls2Conf , noProgress ); err != nil {
228+ if err := vuls2 .DetectCPEs (r , cpes , sesh ); err != nil {
209229 return xerrors .Errorf ("Failed to detect CVE with Vuls2: %w" , err )
210230 }
211231 }
212232 case constant .FreeBSD , constant .ServerTypePseudo :
213233 logging .Log .Infof ("%s type. Skip vuls2 detection" , r .Family )
214234 case constant .Windows :
215- if err := vuls2 .DetectPkgs (r , vuls2Conf , noProgress ); err != nil {
235+ if err := vuls2 .DetectPkgs (r , sesh ); err != nil {
216236 return xerrors .Errorf ("Failed to detect CVE with Vuls2: %w" , err )
217237 }
218238 case constant .RedHat , constant .CentOS , constant .Fedora , constant .Alma , constant .Rocky , constant .Oracle , constant .Amazon ,
@@ -231,7 +251,7 @@ func DetectPkgCves(r *models.ScanResult, vuls2Conf config.Vuls2Conf, noProgress
231251 case len (r .Packages )+ len (r .SrcPackages ) == 0 :
232252 r .Errors = append (r .Errors , xerrors .Errorf ("Failed to detect CVE for %s: no binary or source packages" , r .Family ).Error ())
233253 default :
234- if err := vuls2 .DetectPkgs (r , vuls2Conf , noProgress ); err != nil {
254+ if err := vuls2 .DetectPkgs (r , sesh ); err != nil {
235255 return xerrors .Errorf ("Failed to detect CVE with Vuls2: %w" , err )
236256 }
237257 }
@@ -295,21 +315,23 @@ func DetectWordPressCves(r *models.ScanResult, wpCnf config.WpScanConf) error {
295315}
296316
297317// DetectCpeURIsCves detects CVEs of given CPE-URIs — the complete CPE
298- // detection pipeline, keeping the master-era name and calling convention so
299- // library consumers that drive detection as DetectPkgCves ->
300- // DetectCpeURIsCves keep working.
318+ // detection pipeline, keeping the master-era name and the DetectPkgCves ->
319+ // DetectCpeURIsCves driving order.
301320//
302321// All CPE detection sources (NVD with cpematch-expanded criteria, VulnCheck
303322// NVD++, JVN, Fortinet, Cisco and PaloAlto) are detected by vuls2.
304- func DetectCpeURIsCves (r * models.ScanResult , cpes []vuls2.CPE , vuls2Conf config.Vuls2Conf , noProgress bool ) error {
323+ //
324+ // sesh is the vuls2 db session to query (see vuls2.Session), created with
325+ // vuls2.NewSession and owned (Closed) by the caller.
326+ func DetectCpeURIsCves (r * models.ScanResult , cpes []vuls2.CPE , sesh * vuls2.Session ) error {
305327 // A caller-provided result may carry a nil ScannedCves map (e.g. a
306328 // zero-value ScanResult from a library consumer); initialize before the
307329 // detection paths write into it.
308330 if r .ScannedCves == nil {
309331 r .ScannedCves = models.VulnInfos {}
310332 }
311333
312- if err := vuls2 .DetectCPEs (r , cpes , vuls2Conf , noProgress ); err != nil {
334+ if err := vuls2 .DetectCPEs (r , cpes , sesh ); err != nil {
313335 return xerrors .Errorf ("Failed to detect CVEs with vuls2. err: %w" , err )
314336 }
315337
0 commit comments