Merge ~ebarretto/ubuntu-cve-tracker:oval-kernel-improv into ubuntu-cve-tracker:master

Proposed by Eduardo Barretto
Status: Merged
Merged at revision: 91d5528b3c45c766108d7edb6be9367c72f97b47
Proposed branch: ~ebarretto/ubuntu-cve-tracker:oval-kernel-improv
Merge into: ubuntu-cve-tracker:master
Diff against target: 776 lines (+279/-235)
1 file modified
scripts/oval_lib.py (+279/-235)
Reviewer Review Type Date Requested Status
David Fernandez Gonzalez Approve
Review via email: mp+444569@code.launchpad.net

Description of the change

This PR tries to simplify the kernel check and make it more in line to other package checks where the oval object is pointing to the kernel "uname" and the state is pointing to the fixed version. The way it was before, the object would point to the fixed version and the state was retrieving the kernel uname.
Also fixed some issues with OCI-based kernel regex.

To post a comment you must log in.
Revision history for this message
David Fernandez Gonzalez (litios) wrote :

LGTM! Thanks for taking care of this

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py
2index 2b3d79f..ed64318 100644
3--- a/scripts/oval_lib.py
4+++ b/scripts/oval_lib.py
5@@ -109,9 +109,9 @@ def process_kernel_binaries(binaries, oval_format):
6 version = ''.join(values)
7 values = sorted(set(map(lambda x: x[1], parts)))
8 flavours = '|'.join(values)
9- regex = version + '\d+(' + flavours + ')'
10+ regex = version + '\d+(' + flavours + ')'
11 if oval_format == 'oci':
12- regex = 'linux-image-(?:unsigned-)?' + regex
13+ regex = 'linux-image-(?:unsigned-)?' + version + '\d+(?:' + flavours + ')'
14 return regex
15
16 return None
17@@ -457,8 +457,13 @@ class CVE:
18
19 def add_pkg(self, pkg_object, release, state, note):
20 cve_pkg_entry = CVEPkgRelEntry(pkg_object, release, self, state, note)
21+
22+ if cve_pkg_entry.status in ['not-vulnerable', 'not-applicable']:
23+ return
24+
25 self.pkg_rel_entries[pkg_object.name] = cve_pkg_entry
26 self.pkgs.append(pkg_object)
27+ pkg_object.cves.append(self)
28
29 def __str__(self) -> str:
30 return self.number
31@@ -531,9 +536,7 @@ class OvalGeneratorPkg(OvalGenerator):
32 version = etree.SubElement(advisory, "current_version")
33
34 for cve in package.cves:
35- if cve.pkg_rel_entries[package.name].status == 'not-vulnerable':
36- continue
37- elif self.fixed_only and cve.pkg_rel_entries[package.name].status != 'fixed':
38+ if self.fixed_only and cve.pkg_rel_entries[package.name].status != 'fixed':
39 continue
40 cve_obj = self._generate_cve_object(cve)
41 advisory.append(cve_obj)
42@@ -739,20 +742,17 @@ class OvalGeneratorPkg(OvalGenerator):
43 def _add_running_kernel_checks(self, root_element):
44 objects = root_element.find("objects")
45 variables = root_element.find("variables")
46- states = root_element.find("states")
47
48 variable_local_kernel_check = self._generate_local_variable_kernel(self.definition_id, "Kernel version in evr format", self.definition_id)
49 obj_running_kernel = self._generate_uname_object_element(self.definition_id)
50- state_kernel_version = self._generate_state_kernel_element("Kernel check", self.definition_id, self.definition_id)
51
52 objects.append(obj_running_kernel)
53 variables.append(variable_local_kernel_check)
54- states.append(state_kernel_version)
55
56 def _generate_local_variable_kernel(self, id, comment, uname_obj_id):
57 var = etree.Element("local_variable",
58 attrib={
59- 'id' : f"{self.ns}:var:{id}",
60+ 'id': f"{self.ns}:var:{id}",
61 'version': "1",
62 "datatype": "debian_evr_string",
63 "comment": comment
64@@ -798,20 +798,6 @@ class OvalGeneratorPkg(OvalGenerator):
65
66 return object
67
68- def _generate_variable_kernel_version(self, comment, id, version):
69- var = etree.Element("constant_variable",
70- attrib={
71- 'id' : f"{self.ns}:var:{id}",
72- 'version': "1",
73- "datatype": "debian_evr_string",
74- "comment": comment
75- })
76-
77- item = etree.SubElement(var, "value")
78- item.text = f"0:{version.rsplit('.', 1)[0]}"
79-
80- return var
81-
82 def _generate_test_element_running_kernel(self, id, comment, obj_id):
83 test = etree.Element("unix-def:uname_test", attrib={
84 "id": f"{self.ns}:tst:{id}",
85@@ -846,7 +832,13 @@ class OvalGeneratorPkg(OvalGenerator):
86
87 return object
88
89- def _generate_state_kernel_element(self, comment, id, var_id) -> None:
90+ def _generate_state_kernel_element(self, comment, id, version) -> None:
91+ patched = re.search('([\d|\.]+-\d+)[\.|\d]+', version)
92+ if patched:
93+ patched = patched.group(1)
94+ else:
95+ patched = version
96+
97 state = etree.Element("ind-def:variable_state",
98 attrib={
99 'id' : f"{self.ns}:ste:{id}",
100@@ -854,13 +846,12 @@ class OvalGeneratorPkg(OvalGenerator):
101 "comment": comment
102 })
103
104- etree.SubElement(state, "ind-def:value", attrib={
105+ value = etree.SubElement(state, "ind-def:value", attrib={
106 "datatype": "debian_evr_string",
107- "operation": "greater than",
108- "var_check": "at least one",
109- "var_ref": f"{self.ns}:var:{var_id}"
110+ "operation": "less than",
111 })
112
113+ value.text = f"0:{patched}"
114 return state
115
116 def _generate_kernel_package_elements(self, package: Package, root_element, running_kernel_check_id) -> etree.Element:
117@@ -884,23 +875,29 @@ class OvalGeneratorPkg(OvalGenerator):
118 def _add_fixed_kernel_elements(self, cve: CVE, package: Package, package_rel_entry:CVEPkgRelEntry, root_element, running_kernel_id, fixed_versions) -> etree.Element:
119 tests = root_element.find("tests")
120 objects = root_element.find("objects")
121- variables = root_element.find("variables")
122+ states = root_element.find("states")
123
124- comment_version = f'Kernel {package.name} version comparison ({package_rel_entry.fixed_version})'
125+ comment_version = f'Kernel {package.name} version comparison'
126 comment_criterion = f'({cve.number}) {package.name} {package_rel_entry.note}'
127
128 if package_rel_entry.fixed_version in fixed_versions:
129 criterion_version = self._generate_criterion_element(comment_criterion, fixed_versions[package_rel_entry.fixed_version])
130 else:
131- criterion_version = self._generate_criterion_element(comment_criterion, self.definition_id)
132- test_kernel_version = self._generate_test_element(comment_version, self.definition_id, True, 'kernel', state_id=running_kernel_id)
133+ create_state = False
134+
135+ if package_rel_entry.fixed_version:
136+ create_state = True
137+ ste_kernel_version = self._generate_state_kernel_element("Kernel check", self.definition_id, package_rel_entry.fixed_version)
138+ states.append(ste_kernel_version)
139
140- obj_kernel_version = self._generate_kernel_version_object_element(self.definition_id, self.definition_id)
141- var_version_kernel = self._generate_variable_kernel_version(comment_version, self.definition_id, package_rel_entry.fixed_version)
142+ obj_kernel_version = self._generate_kernel_version_object_element(self.definition_id, running_kernel_id)
143+
144+ test_kernel_version = self._generate_test_element(comment_version, self.definition_id, create_state, 'kernel', self.definition_id)
145+
146+ criterion_version = self._generate_criterion_element(comment_criterion, self.definition_id)
147
148 tests.append(test_kernel_version)
149 objects.append(obj_kernel_version)
150- variables.append(var_version_kernel)
151
152 fixed_versions[package_rel_entry.fixed_version] = self.definition_id
153
154@@ -941,17 +938,19 @@ class OvalGeneratorPkg(OvalGenerator):
155 if not obj_id:
156 object = self._generate_object_object(object_note, self.definition_id, self.definition_id)
157
158- binaries = package.binaries
159+ bins = package.binaries
160+ if is_kernel_binaries(package.binaries):
161+ regex = process_kernel_binaries(package.binaries, 'oci')
162+ bins = [f'{regex}']
163+
164+ binaries = []
165 if self.oval_format == 'oci':
166- if is_kernel_binaries(package.binaries):
167- regex = process_kernel_binaries(package.binaries, 'oci')
168- binaries = [f'^{regex}(?::\w+|)\s+(.*)$\s+(.*)']
169- else:
170- variable_values = '(?::\w+|)\s+(.*)$\s+(.*)'
171+ variable_values = '(?::\w+|)\s+(.*)$'
172+ for binary in bins:
173+ binaries.append(f'^{binary}{variable_values}')
174+ else:
175+ binaries = bins
176
177- binaries = []
178- for binary in package.binaries:
179- binaries.append(f'^{binary}{variable_values}')
180 var = self._generate_var_object(object_note, self.definition_id, binaries)
181 else:
182 object = None
183@@ -972,9 +971,9 @@ class OvalGeneratorPkg(OvalGenerator):
184 if self.oval_format == 'oci':
185 if is_kernel_binaries(package.binaries):
186 regex = process_kernel_binaries(package.binaries, 'oci')
187- binaries = [f'^{regex}(?::\w+|)\s+(.*)$\s+(.*)']
188+ binaries = [f'^{regex}(?::\w+|)\s+(.*)$']
189 else:
190- variable_values = '(?::\w+|)\s+(.*)$\s+(.*)'
191+ variable_values = '(?::\w+|)\s+(.*)$'
192
193 binaries = []
194 for binary in package.binaries:
195@@ -1049,18 +1048,12 @@ class OvalGeneratorPkg(OvalGenerator):
196 self._increase_id(is_definition=True)
197
198 def _populate_kernel_pkg(self, package, root_element, running_kernel_id):
199- tests = root_element.find("tests")
200- objects = root_element.find("objects")
201- variables = root_element.find("variables")
202-
203 # Add package definition
204 definitions = root_element.find("definitions")
205 definition_element = self._generate_definition_object(package)
206
207 # Control/cache variables
208- one_time_added_id = None
209 fixed_versions = {}
210- binaries_id = None
211 cve_added = False
212
213 # Generate one-time elements
214@@ -1072,29 +1065,11 @@ class OvalGeneratorPkg(OvalGenerator):
215
216 for cve in package.cves:
217 pkg_rel_entry = cve.pkg_rel_entries[package.name]
218- if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only:
219- cve_added = True
220- if one_time_added_id:
221- self._add_criterion(one_time_added_id, pkg_rel_entry, cve, definition_element, depth=3)
222- else:
223- self._add_criterion(self.definition_id, pkg_rel_entry, cve, definition_element, depth=3)
224-
225- test, object, var = self._generate_vulnerable_elements(package, binaries_id)
226- tests.append(test)
227- objects.append(object)
228-
229- if not binaries_id:
230- variables.append(var)
231- binaries_id = self.definition_id
232-
233- one_time_added_id = self.definition_id
234- self._increase_id(is_definition=False)
235- elif pkg_rel_entry.status == 'fixed':
236- cve_added = True
237+ cve_added = True
238
239- kernel_version_criterion = self._add_fixed_kernel_elements(cve, package, pkg_rel_entry, root_element, running_kernel_id, fixed_versions)
240- self._add_to_criteria(definition_element, kernel_version_criterion, depth=3)
241- self._increase_id(is_definition=False)
242+ kernel_version_criterion = self._add_fixed_kernel_elements(cve, package, pkg_rel_entry, root_element, running_kernel_id, fixed_versions)
243+ self._add_to_criteria(definition_element, kernel_version_criterion, depth=3)
244+ self._increase_id(is_definition=False)
245
246 if cve_added:
247 definitions.append(definition_element)
248@@ -1111,9 +1086,6 @@ class OvalGeneratorPkg(OvalGenerator):
249 packages[package_name] = pkg_obj
250
251 pkg_obj = packages[package_name]
252- if cve not in pkg_obj.cves:
253- pkg_obj.cves.append(cve)
254-
255 cve.add_pkg(pkg_obj, release, cve_data['pkgs'][package_name][release][0],cve_data['pkgs'][package_name][release][1])
256
257 def _load_pkgs(self, cve_prefix_dir, packages_filter=None) -> None:
258@@ -1262,7 +1234,7 @@ class OvalGeneratorCVE:
259 'id_base': id_base + len(test_refs),
260 'source-note': header['Source-note']
261 }
262- if is_kernel_binaries(pkg['binaries']) and pkg['fix-version']:
263+ if is_kernel_binaries(pkg['binaries']):
264 test_ref = self.get_running_kernel_testref(pkg)
265 if test_ref:
266 test_refs = test_refs + test_ref
267@@ -1324,7 +1296,7 @@ class OvalGeneratorCVE:
268 ' <criterion test_ref="{0}" comment="{1}" {2}/>'.format(
269 test_ref['id'],
270 escape(test_ref['comment']), negation_attribute))
271- criteria.append(' </criteria>')
272+ criteria.append(' </criteria>')
273 else:
274 negation_attribute = 'negate = "true" ' \
275 if 'negate' in test_ref and test_ref['negate'] else ''
276@@ -1401,45 +1373,63 @@ class OvalGeneratorCVE:
277 </criteria>
278 </definition>\n""".format(**mapping))
279
280- def get_running_kernel_testref(self, package):
281- uname_regex = process_kernel_binaries(package['binaries'], self.oval_format)
282- if uname_regex:
283- if self.oval_format == 'dpkg':
284- (var_id, var_id_2) = self.get_running_kernel_variable_id(
285- uname_regex,
286- package['id_base'],
287- package['fix-version'])
288- (ste_id, ste_id_2) = self.get_running_kernel_state_id(
289- uname_regex,
290- package['id_base'],
291- var_id)
292- (obj_id, obj_id_2) = self.get_running_kernel_object_id(
293- package['id_base'], var_id_2)
294- (test_id, test_id_2) = self.get_running_kernel_test_id(
295- uname_regex, package['id_base'], package['name'],
296- obj_id, ste_id, obj_id_2, ste_id_2)
297- return [{'id': test_id,
298- 'comment': 'Is kernel {0} running'.format(package['name']),
299- 'kernel': uname_regex, 'var_id': var_id},
300- {'id': test_id_2, 'comment': 'kernel version comparison',
301- 'kernelobj': True}]
302- else: # OCI
303- object_id = self.get_package_object_id(package['name'],
304- [uname_regex],
305- package['id_base'])
306- state_id = self.get_package_version_state_id(package['id_base'],
307- package['fix-version'])
308- test_title = "Does the '{0}' package exist and is the version less than '{1}'?".format(package['name'],
309- package['fix-version'])
310- test_id = self.get_package_test_id(package['name'],
311- package['id_base'],
312- test_title,
313- object_id,
314- state_id)
315- package['note'] = package['name'] + package['note']
316- return [{'id': test_id, 'comment': package['note']}]
317+ # TODO: xml lib
318+ def add_release_applicability_definition(self):
319+ """ add platform/release applicability OVAL definition for codename """
320+
321+ mapping = {
322+ 'ns': self.ns,
323+ 'id_base': self.id,
324+ 'codename': cve_lib.product_series(self.release)[1],
325+ 'release_name': self.release_name,
326+ }
327+ self.release_applicability_definition_id = \
328+ '{ns}:def:{id_base}0'.format(**mapping)
329+
330+ if self.oval_format == 'dpkg':
331+ self.queue_element('definition', """
332+ <definition class="inventory" id="{ns}:def:{id_base}0" version="1">
333+ <metadata>
334+ <title>Check that {release_name} ({codename}) is installed.</title>
335+ <description></description>
336+ </metadata>
337+ <criteria>
338+ <criterion test_ref="{ns}:tst:{id_base}0" comment="The host is part of the unix family." />
339+ <criterion test_ref="{ns}:tst:{id_base}1" comment="The host is running Ubuntu {codename}." />
340+ </criteria>
341+ </definition>\n""".format(**mapping))
342+
343+ self.queue_element('test', """
344+ <ind-def:family_test id="{ns}:tst:{id_base}0" check="at least one" check_existence="at_least_one_exists" version="1" comment="Is the host part of the unix family?">
345+ <ind-def:object object_ref="{ns}:obj:{id_base}0"/>
346+ <ind-def:state state_ref="{ns}:ste:{id_base}0"/>
347+ </ind-def:family_test>
348+
349+ <ind-def:textfilecontent54_test id="{ns}:tst:{id_base}1" check="at least one" check_existence="at_least_one_exists" version="1" comment="Is the host running Ubuntu {codename}?">
350+ <ind-def:object object_ref="{ns}:obj:{id_base}1"/>
351+ <ind-def:state state_ref="{ns}:ste:{id_base}1"/>
352+ </ind-def:textfilecontent54_test>\n""".format(**mapping))
353+
354+ # /etc/lsb-release has to be a single path, due to some
355+ # environments (namely snaps) not being allowed to list the
356+ # content of /etc/
357+ self.queue_element('object', """
358+ <ind-def:family_object id="{ns}:obj:{id_base}0" version="1" comment="The singleton family object."/>
359+
360+ <ind-def:textfilecontent54_object id="{ns}:obj:{id_base}1" version="1" comment="The singleton release codename object.">
361+ <ind-def:filepath>/etc/lsb-release</ind-def:filepath>
362+ <ind-def:pattern operation="pattern match">^[\\s\\S]*DISTRIB_CODENAME=([a-z]+)$</ind-def:pattern>
363+ <ind-def:instance datatype="int">1</ind-def:instance>
364+ </ind-def:textfilecontent54_object>\n""".format(**mapping))
365+
366+ self.queue_element('state', """
367+ <ind-def:family_state id="{ns}:ste:{id_base}0" version="1" comment="The singleton family object.">
368+ <ind-def:family>unix</ind-def:family>
369+ </ind-def:family_state>
370
371- return None
372+ <ind-def:textfilecontent54_state id="{ns}:ste:{id_base}1" version="1" comment="{release_name}">
373+ <ind-def:subexpression>{codename}</ind-def:subexpression>
374+ </ind-def:textfilecontent54_state>\n""".format(**mapping))
375
376 def get_oval_test_for_package(self, package):
377 """ create OVAL test and dependent objects for this package status
378@@ -1504,64 +1494,6 @@ class OvalGeneratorCVE:
379 return {'id': self.id_unknown_test, 'comment': package['note']}
380
381 # TODO: xml lib
382- def add_release_applicability_definition(self):
383- """ add platform/release applicability OVAL definition for codename """
384-
385- mapping = {
386- 'ns': self.ns,
387- 'id_base': self.id,
388- 'codename': cve_lib.product_series(self.release)[1],
389- 'release_name': self.release_name,
390- }
391- self.release_applicability_definition_id = \
392- '{ns}:def:{id_base}0'.format(**mapping)
393-
394- if self.oval_format == 'dpkg':
395- self.queue_element('definition', """
396- <definition class="inventory" id="{ns}:def:{id_base}0" version="1">
397- <metadata>
398- <title>Check that {release_name} ({codename}) is installed.</title>
399- <description></description>
400- </metadata>
401- <criteria>
402- <criterion test_ref="{ns}:tst:{id_base}0" comment="The host is part of the unix family." />
403- <criterion test_ref="{ns}:tst:{id_base}1" comment="The host is running Ubuntu {codename}." />
404- </criteria>
405- </definition>\n""".format(**mapping))
406-
407- self.queue_element('test', """
408- <ind-def:family_test id="{ns}:tst:{id_base}0" check="at least one" check_existence="at_least_one_exists" version="1" comment="Is the host part of the unix family?">
409- <ind-def:object object_ref="{ns}:obj:{id_base}0"/>
410- <ind-def:state state_ref="{ns}:ste:{id_base}0"/>
411- </ind-def:family_test>
412-
413- <ind-def:textfilecontent54_test id="{ns}:tst:{id_base}1" check="at least one" check_existence="at_least_one_exists" version="1" comment="Is the host running Ubuntu {codename}?">
414- <ind-def:object object_ref="{ns}:obj:{id_base}1"/>
415- <ind-def:state state_ref="{ns}:ste:{id_base}1"/>
416- </ind-def:textfilecontent54_test>\n""".format(**mapping))
417-
418- # /etc/lsb-release has to be a single path, due to some
419- # environments (namely snaps) not being allowed to list the
420- # content of /etc/
421- self.queue_element('object', """
422- <ind-def:family_object id="{ns}:obj:{id_base}0" version="1" comment="The singleton family object."/>
423-
424- <ind-def:textfilecontent54_object id="{ns}:obj:{id_base}1" version="1" comment="The singleton release codename object.">
425- <ind-def:filepath>/etc/lsb-release</ind-def:filepath>
426- <ind-def:pattern operation="pattern match">^[\\s\\S]*DISTRIB_CODENAME=([a-z]+)$</ind-def:pattern>
427- <ind-def:instance datatype="int">1</ind-def:instance>
428- </ind-def:textfilecontent54_object>\n""".format(**mapping))
429-
430- self.queue_element('state', """
431- <ind-def:family_state id="{ns}:ste:{id_base}0" version="1" comment="The singleton family object.">
432- <ind-def:family>unix</ind-def:family>
433- </ind-def:family_state>
434-
435- <ind-def:textfilecontent54_state id="{ns}:ste:{id_base}1" version="1" comment="{release_name}">
436- <ind-def:subexpression>{codename}</ind-def:subexpression>
437- </ind-def:textfilecontent54_state>\n""".format(**mapping))
438-
439- # TODO: xml lib
440 def get_package_object_id(self, name, bin_pkgs, id_base, version=1):
441 """ create unique object for each package and return its OVAL id """
442 if not hasattr(self, 'package_objects'):
443@@ -1589,10 +1521,10 @@ class OvalGeneratorCVE:
444 </linux-def:dpkginfo_object>\n""".format(object_id, version, name, variable_id))
445
446 else:
447- variable_values = '(?::\w+|)\s+(.*)$\s+(.*)</value>\n <value>^'.join(bin_pkgs)
448+ variable_values = '(?::\w+|)\s+(.*)$</value>\n <value>^'.join(bin_pkgs)
449 self.queue_element('variable', """
450 <constant_variable id="{0}" version="{1}" datatype="string" comment="'{2}' package binaries">
451- <value>^{3}(?::\w+|)\s+(.*)$\s+(.*)</value>
452+ <value>^{3}(?::\w+|)\s+(.*)$</value>
453 </constant_variable>\n""".format(variable_id, version, name, variable_values))
454
455 # create an object that references the variable
456@@ -1613,10 +1545,10 @@ class OvalGeneratorCVE:
457 </linux-def:dpkginfo_object>\n""".format(object_id, version, name, bin_pkgs[0]))
458 else:
459 variable_id = '{0}:var:{1}0'.format(self.ns, id_base)
460- variable_values = '(?::\w+|)\s+(.*)$\s+(.*)</value>\n <value>^'.join(bin_pkgs)
461+ variable_values = '(?::\w+|)\s+(.*)$</value>\n <value>^'.join(bin_pkgs)
462 self.queue_element('variable', """
463 <constant_variable id="{0}" version="{1}" datatype="string" comment="'{2}' package binaries">
464- <value>^{3}(?::\w+|)\s+(.*)$\s+(.*)</value>
465+ <value>^{3}(?::\w+|)\s+(.*)$</value>
466 </constant_variable>\n""".format(variable_id, version, name, variable_values))
467 self.queue_element('object', """
468 <ind-def:textfilecontent54_object id="{0}" version="{1}" comment="The '{2}' package binary.">
469@@ -1679,8 +1611,80 @@ class OvalGeneratorCVE:
470
471 return self.package_tests[key]
472
473+ def get_running_kernel_testref(self, package):
474+ if package['status'] == 'not-applicable':
475+ # if the package status is not-applicable, skip it!
476+ return
477+ elif package['status'] == 'not-vulnerable':
478+ # if the packaget status is not-vulnerable, skip it!
479+ return
480+
481+ testref = []
482+ uname_regex = process_kernel_binaries(package['binaries'], self.oval_format)
483+ if uname_regex:
484+ if self.oval_format == 'dpkg':
485+ var_id = self.get_running_kernel_variable_id(
486+ uname_regex,
487+ package['id_base'])
488+ ste_id = self.get_running_kernel_state_id(
489+ uname_regex,
490+ package['id_base'],
491+ var_id)
492+ obj_id = self.get_running_kernel_object_id(
493+ package['id_base'])
494+ test_id = self.get_running_kernel_test_id(
495+ uname_regex, package['id_base'], package['name'],
496+ obj_id, ste_id)
497+ testref.append({'id': test_id,
498+ 'comment': 'Is kernel {0} running'.format(package['name']),
499+ 'kernel': uname_regex,
500+ 'var_id': var_id,
501+ }
502+ )
503+
504+ # even if a cve was not fixed, we should add the test and object
505+ # but not the state as there won't be a fixed version to compare
506+ # with
507+ ste_id = None
508+ if package['fix-version']:
509+ ste_id = self.get_patched_kernel_state_id(
510+ package['id_base'],
511+ package['fix-version']
512+ )
513+
514+ obj_id = self.get_patched_kernel_object_id(package['id_base'],
515+ var_id)
516+ test_id = self.get_patched_kernel_test_id(
517+ package['id_base'],
518+ package['fix-version'],
519+ obj_id, ste_id
520+ )
521+ testref.append({'id': test_id,
522+ 'comment': 'kernel version comparison',
523+ 'kernelobj': True})
524+ else: # OCI
525+ object_id = self.get_package_object_id(package['name'],
526+ [uname_regex],
527+ package['id_base'])
528+ state_id = None
529+ test_title = "Does the '{0}' package exist?".format(package['name'])
530+ if package['fix-version']:
531+ state_id = self.get_package_version_state_id(package['id_base'],
532+ package['fix-version'])
533+ test_title = "Does the '{0}' package exist and is the version less than '{1}'?".format(package['name'],
534+ package['fix-version'])
535+ test_id = self.get_package_test_id(package['name'],
536+ package['id_base'],
537+ test_title,
538+ object_id,
539+ state_id)
540+ package['note'] = package['name'] + package['note']
541+ return [{'id': test_id, 'comment': package['note']}]
542+
543+ return testref
544+
545 # TODO: xml lib
546- def get_running_kernel_object_id(self, id_base, var_id, version=1):
547+ def get_running_kernel_object_id(self, id_base, version=1):
548 """ creates a uname_object so we can use the value from uname -r for
549 mainly two things:
550 1. compare with the return uname is of the same version and flavour
551@@ -1702,15 +1706,7 @@ class OvalGeneratorCVE:
552
553 self.kernel_uname_obj_id = object_id
554
555- object_id_2 = '{0}:obj:{1}0'.format(self.ns, id_base + 1)
556-
557- self.queue_element('object', """
558- <ind-def:variable_object id="{0}" version="{1}">
559- <ind-def:var_ref>{2}</ind-def:var_ref>
560- </ind-def:variable_object>\n""".format(object_id_2, version, var_id))
561-
562-
563- return (self.kernel_uname_obj_id, object_id_2)
564+ return self.kernel_uname_obj_id
565
566 # TODO: xml lib
567 def get_running_kernel_state_id(self, uname_regex, id_base, var_id, version=1):
568@@ -1722,9 +1718,6 @@ class OvalGeneratorCVE:
569 if not hasattr(self, 'uname_states'):
570 self.uname_states = {}
571
572- if not hasattr(self, 'kernel_state_id'):
573- self.kernel_state_id = None
574-
575 if uname_regex not in self.uname_states:
576 state_id = '{0}:ste:{1}0'.format(self.ns, id_base)
577 self.queue_element('state', """
578@@ -1734,19 +1727,10 @@ class OvalGeneratorCVE:
579
580 self.uname_states[uname_regex] = state_id
581
582- if not self.kernel_state_id:
583- state_id_2 = '{0}:ste:{1}0'.format(self.ns, id_base + 1)
584- self.queue_element('state', """
585- <ind-def:variable_state id="{0}" version="{1}">
586- <ind-def:value operation="greater than" datatype="debian_evr_string" var_ref="{2}" var_check="at least one" />
587- </ind-def:variable_state>\n""".format(state_id_2, version, var_id))
588-
589- self.kernel_state_id = state_id_2
590-
591- return (self.uname_states[uname_regex], self.kernel_state_id)
592+ return self.uname_states[uname_regex]
593
594 # TODO: xml lib
595- def get_running_kernel_variable_id(self, uname_regex, id_base, fixed_version, version=1):
596+ def get_running_kernel_variable_id(self, uname_regex, id_base, version=1):
597 """ creates a local variable to store running kernel version in devian evr string"""
598 if not hasattr(self, 'uname_variables'):
599 self.uname_variables = {}
600@@ -1765,21 +1749,10 @@ class OvalGeneratorCVE:
601
602 self.uname_variables['local_variable'] = var_id
603
604- var_id_2 = '{0}:var:{1}0'.format(self.ns, id_base + 1)
605- patched = re.search('([\d|\.]+-\d+)[\.|\d]+', fixed_version)
606- if patched:
607- patched = patched.group(1)
608- else:
609- patched = fixed_version
610- self.queue_element('variable', """
611- <constant_variable id="{0}" version="{1}" datatype="debian_evr_string" comment="patched kernel">
612- <value>0:{2}</value>
613- </constant_variable>""".format(var_id_2, version, patched))
614-
615- return (self.uname_variables['local_variable'], var_id_2)
616+ return self.uname_variables['local_variable']
617
618 # TODO: xml lib
619- def get_running_kernel_test_id(self, uname_regex, id_base, name, object_id, state_id, object_id_2, state_id_2, version=1):
620+ def get_running_kernel_test_id(self, uname_regex, id_base, name, object_id, state_id, version=1):
621 """ create uname test and return its OVAL id """
622 if not hasattr(self, 'uname_tests'):
623 self.uname_tests = {}
624@@ -1794,16 +1767,94 @@ class OvalGeneratorCVE:
625
626 self.uname_tests[uname_regex] = test_id
627
628- test_id_2 = '{0}:tst:{1}0'.format(self.ns, id_base + 1)
629+ return self.uname_tests[uname_regex]
630+
631+ def get_patched_kernel_variable_id(self, id_base, fixed_version, version=1):
632+ """ creates a local variable to store the patched kernel version """
633+ if not hasattr(self, 'patched_kernel_variables'):
634+ self.patched_kernel_variables = {}
635+
636+ patched = re.search('([\d|\.]+-\d+)[\.|\d]+', fixed_version)
637+ if patched:
638+ patched = patched.group(1)
639+ else:
640+ patched = fixed_version
641+
642+ if patched not in self.patched_kernel_variables:
643+ var_id = '{0}:var:{1}0'.format(self.ns, id_base + 1)
644+
645+ self.queue_element('variable', """
646+ <constant_variable id="{0}" version="{1}" datatype="debian_evr_string" comment="patched kernel">
647+ <value>0:{2}</value>
648+ </constant_variable>""".format(var_id, version, patched))
649+
650+ self.patched_kernel_variables[patched] = var_id
651+
652+ return self.patched_kernel_variables[patched]
653+
654+ def get_patched_kernel_object_id(self, id_base, var_id, version=1):
655+ """ create variable object that points to kernel version
656+ in evr format in local_variable
657+ """
658+
659+ object_id = '{0}:obj:{1}0'.format(self.ns, id_base + 1)
660+
661+ self.queue_element('object', """
662+ <ind-def:variable_object id="{0}" version="{1}">
663+ <ind-def:var_ref>{2}</ind-def:var_ref>
664+ </ind-def:variable_object>\n""".format(object_id, version, var_id))
665+
666+ return object_id
667+
668+ # TODO: xml lib
669+ def get_patched_kernel_state_id(self, id_base, fixed_version, version=1):
670+ """ create state to compare to the running kernel
671+ Return its OVAL id
672+ """
673+ if not hasattr(self, 'patched_kernel_states'):
674+ self.patched_kernel_states = {}
675+
676+ patched = re.search('([\d|\.]+-\d+)[\.|\d]+', fixed_version)
677+ if patched:
678+ patched = patched.group(1)
679+ else:
680+ patched = fixed_version
681+
682+ if patched not in self.patched_kernel_states:
683+ state_id = '{0}:ste:{1}0'.format(self.ns, id_base + 1)
684
685- self.queue_element('test', """
686+ self.queue_element('state', """
687+ <ind-def:variable_state id="{0}" version="{1}">
688+ <ind-def:value datatype="debian_evr_string" operation="less than">{2}</ind-def:value>
689+ </ind-def:variable_state>\n""".format(state_id, version, patched))
690+
691+ self.patched_kernel_states[patched] = state_id
692+
693+ return self.patched_kernel_states[patched]
694+
695+ def get_patched_kernel_test_id(self, id_base, fixed_version, object_id, state_id, version=1):
696+ """ create patched kernel test and return its OVAL id """
697+ if not hasattr(self, 'patched_kernel_tests'):
698+ self.patched_kernel_tests = {}
699+
700+ if fixed_version not in self.patched_kernel_tests:
701+ test_id = '{0}:tst:{1}0'.format(self.ns, id_base + 1)
702+
703+ if state_id:
704+ self.queue_element('test', """
705 <ind-def:variable_test id="{0}" version="1" check="all" check_existence="all_exist" comment="kernel version comparison">
706 <ind-def:object object_ref="{1}"/>
707 <ind-def:state state_ref="{2}"/>
708- </ind-def:variable_test>\n""".format(test_id_2, object_id_2, state_id_2))
709+ </ind-def:variable_test>\n""".format(test_id, object_id, state_id))
710+ else:
711+ self.queue_element('test', """
712+ <ind-def:variable_test id="{0}" version="1" check="all" check_existence="all_exist" comment="kernel version comparison">
713+ <ind-def:object object_ref="{1}"/>
714+ </ind-def:variable_test>\n""".format(test_id, object_id))
715
716+ self.patched_kernel_tests[fixed_version] = test_id
717
718- return (self.uname_tests[uname_regex], test_id_2)
719+ return self.patched_kernel_tests[fixed_version]
720
721 def queue_element(self, element, xml):
722 """ add an OVAL element to an output queue file """
723@@ -2247,11 +2298,12 @@ class OvalGeneratorUSN():
724 <unix:uname_object id="{ns}:obj:{id}" version="1"/>""".format(**mapping)
725
726 elif 'kernelobj' in test_ref:
727+ mapping['varid'] = test_ref['kernelobj']
728
729 _object = \
730 """
731 <ind:variable_object id="{ns}:obj:{id}" version="1">
732- <ind:var_ref>{ns}:var:{id}</ind:var_ref>
733+ <ind:var_ref>{ns}:var:{varid}</ind:var_ref>
734 </ind:variable_object>""".format(**mapping)
735
736 elif self.pocket == "livepatch":
737@@ -2309,11 +2361,14 @@ class OvalGeneratorUSN():
738 </unix:uname_state>""".format(**mapping)
739
740 elif 'kernelobj' in test_ref:
741- mapping['varid'] = test_ref['kernelobj']
742+ binary_version = test_ref['version']
743+ binary_version = re.search('([\d|\.]+-\d+)[\.|\d]+', binary_version)
744+ mapping['bversion'] = "0:" + binary_version.group(1)
745+
746 state = \
747 """
748 <ind:variable_state id="{ns}:ste:{id}" version="1">
749- <ind:value operation="greater than" datatype="debian_evr_string" var_ref="{ns}:var:{varid}" var_check="at least one" />
750+ <ind:value datatype="debian_evr_string" operation="less than">{bversion}</ind:value>
751 </ind:variable_state>""".format(**mapping)
752
753 elif self.pocket == "livepatch":
754@@ -2374,21 +2429,10 @@ class OvalGeneratorUSN():
755 </regex_capture>
756 </concat>
757 </local_variable>""".format(**mapping)
758-
759 return variable
760
761 elif 'kernelobj' in test_ref:
762- binary_version = test_ref['version']
763- binary_version = re.search('([\d|\.]+-\d+)[\.|\d]+', binary_version)
764- mapping['bversion'] = "0:" + binary_version.group(1)
765-
766- variable = \
767- """
768- <constant_variable id="{ns}:var:{id}" version="1" datatype="debian_evr_string" comment="patched kernel">
769- <value>{bversion}</value>
770- </constant_variable>""".format(**mapping)
771-
772- return variable
773+ return
774
775 else:
776 for binary in binaries_list:

Subscribers

People subscribed via source and target branches