Completed
Push — master ( b2d913...ec4189 )
by kota
09:54 queued 04:05
created

gost/redhat.go   C

Size/Duplication

Total Lines 250
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 54
eloc 174
dl 0
loc 250
rs 6.4799
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
F gost.RedHat.fillFixed 0 45 14
A gost.RedHat.FillWithGost 0 5 2
B gost.RedHat.mergePackageStates 0 30 8
F gost.RedHat.fillUnfixed 0 85 19
C gost.RedHat.ConvertToModel 0 56 11
1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Architect, Inc. Japan.
3
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
package gost
19
20
import (
21
	"encoding/json"
22
	"strconv"
23
	"strings"
24
25
	"github.com/future-architect/vuls/config"
26
	"github.com/future-architect/vuls/models"
27
	"github.com/future-architect/vuls/util"
28
	"github.com/knqyf263/gost/db"
29
	gostmodels "github.com/knqyf263/gost/models"
30
)
31
32
// RedHat is Gost client for RedHat family linux
33
type RedHat struct {
34
	Base
35
}
36
37
// FillWithGost fills cve information that has in Gost
38
func (red RedHat) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
39
	if nCVEs, err = red.fillUnfixed(driver, r); err != nil {
40
		return 0, err
41
	}
42
	return nCVEs, red.fillFixed(driver, r)
43
}
44
45
func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
46
	var cveIDs []string
47
	for cveID, vuln := range r.ScannedCves {
48
		if _, ok := vuln.CveContents[models.RedHatAPI]; ok {
49
			continue
50
		}
51
		cveIDs = append(cveIDs, cveID)
52
	}
53
54
	if red.isFetchViaHTTP() {
55
		prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
56
			"redhat", "cves")
57
		responses, err := getCvesViaHTTP(cveIDs, prefix)
58
		if err != nil {
59
			return err
60
		}
61
		for _, res := range responses {
62
			redCve := gostmodels.RedhatCVE{}
63
			if err := json.Unmarshal([]byte(res.json), &redCve); err != nil {
64
				return err
65
			}
66
			if redCve.ID == 0 {
67
				continue
68
			}
69
			cveCont := red.ConvertToModel(&redCve)
70
			v, _ := r.ScannedCves[res.request.cveID]
71
			v.CveContents[models.RedHatAPI] = *cveCont
72
			r.ScannedCves[res.request.cveID] = v
73
		}
74
	} else {
75
		if driver == nil {
76
			return nil
77
		}
78
		for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
79
			if redCve.ID == 0 {
80
				continue
81
			}
82
			cveCont := red.ConvertToModel(&redCve)
83
			v, _ := r.ScannedCves[cveID]
84
			v.CveContents[models.RedHatAPI] = *cveCont
85
			r.ScannedCves[cveID] = v
86
		}
87
	}
88
89
	return nil
90
}
91
92
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
93
	if red.isFetchViaHTTP() {
94
		prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
95
			"redhat", major(r.Release), "pkgs")
96
		responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
97
		if err != nil {
98
			return 0, err
99
		}
100
		for _, res := range responses {
101
			// CVE-ID: RedhatCVE
102
			cves := map[string]gostmodels.RedhatCVE{}
103
			if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
104
				return 0, err
105
			}
106
107
			for _, cve := range cves {
108
				cveCont := red.ConvertToModel(&cve)
109
				v, ok := r.ScannedCves[cve.Name]
110
				if ok {
111
					if _, ok := v.CveContents[models.RedHatAPI]; ok {
112
						v.CveContents[models.RedHatAPI] = *cveCont
113
					} else {
114
						v = models.VulnInfo{
115
							CveID:       cveCont.CveID,
116
							CveContents: models.NewCveContents(*cveCont),
117
							Confidences: models.Confidences{models.RedHatAPIMatch},
118
						}
119
					}
120
				} else {
121
					v = models.VulnInfo{
122
						CveID:       cveCont.CveID,
123
						CveContents: models.NewCveContents(*cveCont),
124
						Confidences: models.Confidences{models.RedHatAPIMatch},
125
					}
126
					nCVEs++
127
				}
128
129
				pkgStats := red.mergePackageStates(v,
130
					cve.PackageState, r.Packages, r.Release)
131
				if 0 < len(pkgStats) {
132
					v.AffectedPackages = pkgStats
133
					r.ScannedCves[cve.Name] = v
134
				}
135
			}
136
		}
137
	} else {
138
		if driver == nil {
139
			return 0, nil
140
		}
141
		for _, pack := range r.Packages {
142
			// CVE-ID: RedhatCVE
143
			cves := map[string]gostmodels.RedhatCVE{}
144
			cves = driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name)
145
			for _, cve := range cves {
146
				cveCont := red.ConvertToModel(&cve)
147
				v, ok := r.ScannedCves[cve.Name]
148
				if ok {
149
					if _, ok := v.CveContents[models.RedHatAPI]; ok {
150
						v.CveContents[models.RedHatAPI] = *cveCont
151
					} else {
152
						v = models.VulnInfo{
153
							CveID:       cveCont.CveID,
154
							CveContents: models.NewCveContents(*cveCont),
155
							Confidences: models.Confidences{models.RedHatAPIMatch},
156
						}
157
					}
158
				} else {
159
					v = models.VulnInfo{
160
						CveID:       cveCont.CveID,
161
						CveContents: models.NewCveContents(*cveCont),
162
						Confidences: models.Confidences{models.RedHatAPIMatch},
163
					}
164
					nCVEs++
165
				}
166
167
				pkgStats := red.mergePackageStates(v,
168
					cve.PackageState, r.Packages, r.Release)
169
				if 0 < len(pkgStats) {
170
					v.AffectedPackages = pkgStats
171
					r.ScannedCves[cve.Name] = v
172
				}
173
			}
174
		}
175
	}
176
	return nCVEs, nil
177
}
178
179
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageStatuses) {
180
	pkgStats = v.AffectedPackages
181
	for _, pstate := range ps {
182
		if pstate.Cpe !=
183
			"cpe:/o:redhat:enterprise_linux:"+major(release) {
184
			return
185
		}
186
187
		if !(pstate.FixState == "Will not fix" ||
188
			pstate.FixState == "Fix deferred") {
189
			return
190
		}
191
192
		if _, ok := installed[pstate.PackageName]; !ok {
193
			return
194
		}
195
196
		notFixedYet := false
197
		switch pstate.FixState {
198
		case "Will not fix", "Fix deferred":
199
			notFixedYet = true
200
		}
201
202
		pkgStats = pkgStats.Store(models.PackageStatus{
203
			Name:        pstate.PackageName,
204
			FixState:    pstate.FixState,
205
			NotFixedYet: notFixedYet,
206
		})
207
	}
208
	return
209
}
210
211
// ConvertToModel converts gost model to vuls model
212
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
213
	cwes := []string{}
214
	if cve.Cwe != "" {
215
		s := strings.TrimPrefix(cve.Cwe, "(")
216
		s = strings.TrimSuffix(s, ")")
217
		if strings.Contains(cve.Cwe, "|") {
218
			cwes = strings.Split(cve.Cwe, "|")
219
		} else {
220
			cwes = strings.Split(s, "->")
221
		}
222
	}
223
224
	details := []string{}
225
	for _, detail := range cve.Details {
226
		details = append(details, detail.Detail)
227
	}
228
229
	v2score := 0.0
230
	if cve.Cvss.CvssBaseScore != "" {
231
		v2score, _ = strconv.ParseFloat(cve.Cvss.CvssBaseScore, 64)
232
	}
233
	v2severity := ""
234
	if v2score != 0 {
235
		v2severity = cve.ThreatSeverity
236
	}
237
238
	v3score := 0.0
239
	if cve.Cvss3.Cvss3BaseScore != "" {
240
		v3score, _ = strconv.ParseFloat(cve.Cvss3.Cvss3BaseScore, 64)
241
	}
242
	v3severity := ""
243
	if v3score != 0 {
244
		v3severity = cve.ThreatSeverity
245
	}
246
247
	var refs []models.Reference
248
	for _, r := range cve.References {
249
		refs = append(refs, models.Reference{Link: r.Reference})
250
	}
251
252
	return &models.CveContent{
253
		Type:          models.RedHatAPI,
254
		CveID:         cve.Name,
255
		Title:         cve.Bugzilla.Description,
256
		Summary:       strings.Join(details, "\n"),
257
		Cvss2Score:    v2score,
258
		Cvss2Vector:   cve.Cvss.CvssScoringVector,
259
		Cvss2Severity: v2severity,
260
		Cvss3Score:    v3score,
261
		Cvss3Vector:   cve.Cvss3.Cvss3ScoringVector,
262
		Cvss3Severity: v3severity,
263
		References:    refs,
264
		CweIDs:        cwes,
265
		Mitigation:    cve.Mitigation,
266
		Published:     cve.PublicDate,
267
		SourceLink:    "https://access.redhat.com/security/cve/" + cve.Name,
268
	}
269
}
270