oval.Ubuntu.FillWithOval   F
last analyzed

Complexity

Conditions 18

Size

Total Lines 93
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 63
dl 0
loc 93
rs 1.2
c 0
b 0
f 0
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like oval.Ubuntu.FillWithOval often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Corporation , 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 oval
19
20
import (
21
	"github.com/future-architect/vuls/config"
22
	"github.com/future-architect/vuls/models"
23
	"github.com/future-architect/vuls/util"
24
	"github.com/kotakanbe/goval-dictionary/db"
25
	ovalmodels "github.com/kotakanbe/goval-dictionary/models"
26
)
27
28
// DebianBase is the base struct of Debian and Ubuntu
29
type DebianBase struct {
30
	Base
31
}
32
33
func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) {
34
	ovalContent := *o.convertToModel(&defPacks.def)
35
	ovalContent.Type = models.NewCveContentType(o.family)
36
	vinfo, ok := r.ScannedCves[defPacks.def.Debian.CveID]
37
	if !ok {
38
		util.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID)
39
		vinfo = models.VulnInfo{
40
			CveID:       defPacks.def.Debian.CveID,
41
			Confidences: []models.Confidence{models.OvalMatch},
42
			CveContents: models.NewCveContents(ovalContent),
43
		}
44
	} else {
45
		cveContents := vinfo.CveContents
46
		ctype := models.NewCveContentType(o.family)
47
		if _, ok := vinfo.CveContents[ctype]; ok {
48
			util.Log.Debugf("%s OVAL will be overwritten",
49
				defPacks.def.Debian.CveID)
50
		} else {
51
			util.Log.Debugf("%s is also detected by OVAL",
52
				defPacks.def.Debian.CveID)
53
			cveContents = models.CveContents{}
54
		}
55
		vinfo.Confidences.AppendIfMissing(models.OvalMatch)
56
		cveContents[ctype] = ovalContent
57
		vinfo.CveContents = cveContents
58
	}
59
60
	// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
61
	for _, pack := range vinfo.AffectedPackages {
62
		defPacks.actuallyAffectedPackNames[pack.Name] = pack.NotFixedYet
63
	}
64
65
	// update notFixedYet of SrcPackage
66
	for binName := range defPacks.actuallyAffectedPackNames {
67
		if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
68
			for _, p := range defPacks.def.AffectedPacks {
69
				if p.Name == srcPack.Name {
70
					defPacks.actuallyAffectedPackNames[binName] = p.NotFixedYet
71
				}
72
			}
73
		}
74
	}
75
76
	vinfo.AffectedPackages = defPacks.toPackStatuses()
77
	vinfo.AffectedPackages.Sort()
78
	r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
79
}
80
81
func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveContent {
82
	var refs []models.Reference
83
	for _, r := range def.References {
84
		refs = append(refs, models.Reference{
85
			Link:   r.RefURL,
86
			Source: r.Source,
87
			RefID:  r.RefID,
88
		})
89
	}
90
91
	return &models.CveContent{
92
		CveID:         def.Debian.CveID,
93
		Title:         def.Title,
94
		Summary:       def.Description,
95
		Cvss2Severity: def.Advisory.Severity,
96
		References:    refs,
97
	}
98
}
99
100
// Debian is the interface for Debian OVAL
101
type Debian struct {
102
	DebianBase
103
}
104
105
// NewDebian creates OVAL client for Debian
106
func NewDebian() Debian {
107
	return Debian{
108
		DebianBase{
109
			Base{
110
				family: config.Debian,
111
			},
112
		},
113
	}
114
}
115
116
// FillWithOval returns scan result after updating CVE info by OVAL
117
func (o Debian) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
118
119
	//Debian's uname gives both of kernel release(uname -r), version(kernel-image version)
120
	linuxImage := "linux-image-" + r.RunningKernel.Release
121
122
	// Add linux and set the version of running kernel to search OVAL.
123
	if r.Container.ContainerID == "" {
124
		newVer := ""
125
		if p, ok := r.Packages[linuxImage]; ok {
126
			newVer = p.NewVersion
127
		}
128
		r.Packages["linux"] = models.Package{
129
			Name:       "linux",
130
			Version:    r.RunningKernel.Version,
131
			NewVersion: newVer,
132
		}
133
	}
134
135
	var relatedDefs ovalResult
136
	if config.Conf.OvalDict.IsFetchViaHTTP() {
137
		if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
138
			return 0, err
139
		}
140
	} else {
141
		if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
142
			return 0, err
143
		}
144
	}
145
146
	delete(r.Packages, "linux")
147
148
	for _, defPacks := range relatedDefs.entries {
149
		// Remove "linux" added above for oval search
150
		// linux is not a real package name (key of affected packages in OVAL)
151
		if notFixedYet, ok := defPacks.actuallyAffectedPackNames["linux"]; ok {
152
			defPacks.actuallyAffectedPackNames[linuxImage] = notFixedYet
153
			delete(defPacks.actuallyAffectedPackNames, "linux")
154
			for i, p := range defPacks.def.AffectedPacks {
155
				if p.Name == "linux" {
156
					p.Name = linuxImage
157
					defPacks.def.AffectedPacks[i] = p
158
				}
159
			}
160
		}
161
162
		o.update(r, defPacks)
163
	}
164
165
	for _, vuln := range r.ScannedCves {
166
		if cont, ok := vuln.CveContents[models.Debian]; ok {
167
			cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
168
			vuln.CveContents[models.Debian] = cont
169
		}
170
	}
171
	return len(relatedDefs.entries), nil
172
}
173
174
// Ubuntu is the interface for Debian OVAL
175
type Ubuntu struct {
176
	DebianBase
177
}
178
179
// NewUbuntu creates OVAL client for Debian
180
func NewUbuntu() Ubuntu {
181
	return Ubuntu{
182
		DebianBase{
183
			Base{
184
				family: config.Ubuntu,
185
			},
186
		},
187
	}
188
}
189
190
// FillWithOval returns scan result after updating CVE info by OVAL
191
func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
192
	ovalKernelImageNames := []string{
193
		"linux-aws",
194
		"linux-azure",
195
		"linux-flo",
196
		"linux-gcp",
197
		"linux-gke",
198
		"linux-goldfish",
199
		"linux-hwe",
200
		"linux-hwe-edge",
201
		"linux-kvm",
202
		"linux-mako",
203
		"linux-raspi2",
204
		"linux-snapdragon",
205
	}
206
	linuxImage := "linux-image-" + r.RunningKernel.Release
207
208
	found := false
209
	if r.Container.ContainerID == "" {
210
		for _, n := range ovalKernelImageNames {
211
			if _, ok := r.Packages[n]; ok {
212
				v, ok := r.Packages[linuxImage]
213
				if ok {
214
					// Set running kernel version
215
					p := r.Packages[n]
216
					p.Version = v.Version
217
					p.NewVersion = v.NewVersion
218
					r.Packages[n] = p
219
				} else {
220
					util.Log.Warnf("Running kernel image %s is not found: %s",
221
						linuxImage, r.RunningKernel.Version)
222
				}
223
				found = true
224
				break
225
			}
226
		}
227
228
		if !found {
229
			// linux-generic is described as "linux" in Ubuntu's oval.
230
			// Add "linux" and set the version of running kernel to search OVAL.
231
			v, ok := r.Packages[linuxImage]
232
			if ok {
233
				r.Packages["linux"] = models.Package{
234
					Name:       "linux",
235
					Version:    v.Version,
236
					NewVersion: v.NewVersion,
237
				}
238
			} else {
239
				util.Log.Warnf("%s is not found. Running: %s",
240
					linuxImage, r.RunningKernel.Release)
241
			}
242
		}
243
	}
244
245
	var relatedDefs ovalResult
246
	if config.Conf.OvalDict.IsFetchViaHTTP() {
247
		if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
248
			return 0, err
249
		}
250
	} else {
251
		if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
252
			return 0, err
253
		}
254
	}
255
256
	if !found {
257
		delete(r.Packages, "linux")
258
	}
259
260
	for _, defPacks := range relatedDefs.entries {
261
		// Remove "linux" added above to search for oval
262
		// "linux" is not a real package name (key of affected packages in OVAL)
263
		if _, ok := defPacks.actuallyAffectedPackNames["linux"]; !found && ok {
264
			defPacks.actuallyAffectedPackNames[linuxImage] = true
265
			delete(defPacks.actuallyAffectedPackNames, "linux")
266
			for i, p := range defPacks.def.AffectedPacks {
267
				if p.Name == "linux" {
268
					p.Name = linuxImage
269
					defPacks.def.AffectedPacks[i] = p
270
				}
271
			}
272
		}
273
274
		o.update(r, defPacks)
275
	}
276
277
	for _, vuln := range r.ScannedCves {
278
		if cont, ok := vuln.CveContents[models.Ubuntu]; ok {
279
			cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
280
			vuln.CveContents[models.Ubuntu] = cont
281
		}
282
	}
283
	return len(relatedDefs.entries), nil
284
}
285