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

Proposed by Eduardo Barretto
Status: Merged
Merged at revision: 0defaa0b0b8dbae7c5794aaa8c71f459162712fa
Proposed branch: ~ebarretto/ubuntu-cve-tracker:oval-meta-kernel
Merge into: ubuntu-cve-tracker:master
Diff against target: 191 lines (+78/-57)
2 files modified
scripts/generate-oval (+1/-25)
scripts/oval_lib.py (+77/-32)
Reviewer Review Type Date Requested Status
Ubuntu Security Team Pending
Review via email: mp+437896@code.launchpad.net

Description of the change

This PR tries to solve some kernel false positives caused by meta kernels. To solve it, I removed the meta kernels completely from OVAL. Also it adds some kernel helper functions just to add consistency and reduce code duplication.

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

LGTM!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/scripts/generate-oval b/scripts/generate-oval
2index 849ef82..b6dd88e 100755
3--- a/scripts/generate-oval
4+++ b/scripts/generate-oval
5@@ -37,7 +37,7 @@ import tempfile
6
7 import apt_pkg
8 from cve_lib import (kernel_srcs, product_series, load_cve, PRODUCT_UBUNTU, all_releases, eol_releases, devel_release, release_parent, release_name, release_ppa, release_progenitor, needs_oval)
9-from kernel_lib import (meta_kernels, kernel_package_abi, kernel_package_version)
10+from kernel_lib import meta_kernels
11 import oval_lib
12 import lpl_common
13
14@@ -365,30 +365,6 @@ def parse_cve_file(filepath, cache, pkg_filter=None):
15 rel for rel in packages[package]['Releases']
16 if packages[package]['Releases'][rel]['status'] != 'not-applicable'
17 ]:
18- # add meta package
19- # handle meta package of subprojects without needing to have them in kernel_lib
20- progenitor = release_progenitor(release)
21- if progenitor:
22- meta_pkg = meta_kernels.get_meta(progenitor, package, quiet=(debug_level < 1))
23- else:
24- meta_pkg = meta_kernels.get_meta(release, package, quiet=(debug_level < 1))
25- if meta_pkg:
26- if meta_pkg not in packages:
27- packages[meta_pkg] = {
28- 'Priority': packages[package]['Priority'],
29- 'Tags': packages[package]['Tags'],
30- 'Releases': {}
31- }
32- if release not in packages[meta_pkg]['Releases']:
33- kernel_status = packages[package]['Releases'][release]
34- # kernel meta packages have a different versioning
35- # scheme derived from the kernel version + kernel abi
36- meta_version = None
37- if 'fix-version' in kernel_status:
38- meta_version = '%s.%s' % (kernel_package_version(kernel_status['fix-version']),
39- kernel_package_abi(kernel_status['fix-version']))
40- packages[meta_pkg]['Releases'][release] = \
41- duplicate_package_status(release, meta_pkg, kernel_status, cache, override_version=meta_version)
42 # add signed package
43 # handle signed package of subprojects without needing to have them in kernel_lib
44 progenitor = release_progenitor(release)
45diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py
46index 6c7fa7f..e70a6f1 100644
47--- a/scripts/oval_lib.py
48+++ b/scripts/oval_lib.py
49@@ -79,6 +79,35 @@ by updating your system to the following package versions:""".format(cve)
50
51 return instruction
52
53+def is_kernel_binaries(binaries):
54+ reg = re.compile('linux-image-.*')
55+ if any(filter(reg.match, binaries)):
56+ return True
57+ return False
58+
59+
60+""" Using the following kernel uname, we can understand its format:
61+ uname -r -> 5.4.0-1059-generic
62+ MAJOR_VERSION="5.4.0"
63+ ABI="1059"
64+ FLAVOUR="generic"
65+"""
66+def process_kernel_binaries(binaries, oval_format):
67+ packages = ' '.join(binaries)
68+ parts = re.findall('linux-image-[a-z]*-?([\d|\.]+-)\d+(-[\w|-]+)', packages)
69+ if parts:
70+ values = set(map(lambda x: x[0], parts))
71+ version = ''.join(values)
72+ values = set(map(lambda x: x[1], parts))
73+ flavours = '|'.join(values)
74+ regex = version + '\d+(' + flavours + ')'
75+ if oval_format == 'oci':
76+ regex = 'linux-image-(?:unsigned-)?' + regex
77+ return regex
78+
79+ return None
80+
81+
82 class OvalGenerator:
83 supported_oval_elements = ('definition', 'test', 'object', 'state',
84 'variable')
85@@ -138,7 +167,7 @@ class OvalGenerator:
86 'id_base': id_base + len(test_refs),
87 'source-note': header['Source-note']
88 }
89- if package.startswith('linux') and self.oval_format == 'dpkg' and pkg['fix-version']:
90+ if is_kernel_binaries(pkg['binaries']) and pkg['fix-version']:
91 test_ref = self.get_running_kernel_testref(pkg)
92 if test_ref:
93 test_refs = test_refs + test_ref
94@@ -277,25 +306,44 @@ class OvalGenerator:
95 </definition>\n""".format(**mapping))
96
97 def get_running_kernel_testref(self, package):
98- """ Using the following kernel uname, we can understand its format:
99- uname -r -> 5.4.0-1059-generic
100- MAJOR_VERSION="5.4.0"
101- ABI="1059"
102- FLAVOUR="generic"
103- """
104- for pkg in package['binaries']:
105- uname = re.search('linux-image-[a-z]*-?([\d|\.]+-)(\d+)(-[\w|-]+)', pkg)
106- if uname:
107- uname_regex = uname.group(1) + '\d{' + str(len(uname.group(2))) + '}' + uname.group(3)
108- (var_id, var_id_2) = self.get_running_kernel_variable_id(uname_regex, package['id_base'], package['fix-version'])
109- (ste_id, ste_id_2) = self.get_running_kernel_state_id(uname_regex, package['id_base'], var_id)
110- (obj_id, obj_id_2) = self.get_running_kernel_object_id(package['id_base'], var_id_2)
111- (test_id, test_id_2) = self.get_running_kernel_test_id(uname_regex, package['id_base'], package['name'],
112- obj_id, ste_id, obj_id_2, ste_id_2)
113- return [{'id': test_id, 'comment': 'Is kernel {0} running'.format(package['name']),
114- 'kernel': uname_regex, 'var_id': var_id}, {'id': test_id_2, 'comment': 'kernel version comparison', 'kernelobj': True}]
115-
116- return None
117+ uname_regex = process_kernel_binaries(package['binaries'], self.oval_format)
118+ if uname_regex:
119+ if self.oval_format == 'dpkg':
120+ (var_id, var_id_2) = self.get_running_kernel_variable_id(
121+ uname_regex,
122+ package['id_base'],
123+ package['fix-version'])
124+ (ste_id, ste_id_2) = self.get_running_kernel_state_id(
125+ uname_regex,
126+ package['id_base'],
127+ var_id)
128+ (obj_id, obj_id_2) = self.get_running_kernel_object_id(
129+ package['id_base'], var_id_2)
130+ (test_id, test_id_2) = self.get_running_kernel_test_id(
131+ uname_regex, package['id_base'], package['name'],
132+ obj_id, ste_id, obj_id_2, ste_id_2)
133+ return [{'id': test_id,
134+ 'comment': 'Is kernel {0} running'.format(package['name']),
135+ 'kernel': uname_regex, 'var_id': var_id},
136+ {'id': test_id_2, 'comment': 'kernel version comparison',
137+ 'kernelobj': True}]
138+ else: # OCI
139+ object_id = self.get_package_object_id(package['name'],
140+ uname_regex,
141+ package['id_base'])
142+ state_id = self.get_package_version_state_id(package['id_base'],
143+ package['fix-version'])
144+ test_title = "Does the '{0}' package exist and is the version less than '{1}'?".format(package['name'],
145+ package['fix-version'])
146+ test_id = self.get_package_test_id(package['name'],
147+ package['id_base'],
148+ test_title,
149+ object_id,
150+ state_id)
151+ package['note'] = package['name'] + package['note']
152+ return [{'id': test_id, 'comment': package['note']}]
153+
154+ return None
155
156 def get_oval_test_for_package(self, package):
157 """ create OVAL test and dependent objects for this package status
158@@ -1314,25 +1362,22 @@ class OvalGeneratorUSN():
159 return version_map
160
161 def get_testref(self, version, pkgs, testref_id):
162- reg = re.compile('linux-image-.*')
163- if any(filter(reg.match, pkgs)) and self.oval_format == 'dpkg':
164- for pkg in pkgs:
165- uname = re.search('linux-image-[a-z]*-?([\d|\.]+-)(\d+)(-[\w|-]+)', pkg)
166- if uname:
167- # transform pkgs list into string to make it easy to
168- # get all flavours at once in a list
169- packages = ' '.join(pkgs)
170- flavours = set(re.findall('linux-image-[a-z]*-?[\d|\.]+-\d+-([\w|-]+)', packages))
171- name = uname.group(1) + '\d{' + str(len(uname.group(2))) + '}-(' + '|'.join(flavours) + ')'
172+ if is_kernel_binaries(pkgs):
173+ uname_regex = process_kernel_binaries(pkgs, self.oval_format)
174+ if uname_regex:
175+ if self.oval_format == 'dpkg':
176 new_id = '{0}0'.format(testref_id)
177 new_id_2 = '{0}0'.format(testref_id + 1)
178 # kernel has two test_ref:
179 # 1. check if running kernel is of same version and flavour as patched
180 # 2. check if running kernel is less than patched kernel
181- return ({'version': version, 'pkgs': [uname.group(0)],
182- 'testref_id': new_id, 'kernel': name},
183+ return ({'version': version, 'pkgs': pkgs,
184+ 'testref_id': new_id, 'kernel': uname_regex},
185 {'version': version, 'pkgs': pkgs,
186 'testref_id': new_id_2, 'kernelobj': new_id})
187+ else:
188+ new_id = '{0}0'.format(testref_id)
189+ return({'version': version, 'pkgs': [uname_regex], 'testref_id': new_id}, None)
190
191 return (None, None)
192

Subscribers

People subscribed via source and target branches