Merge ~ebarretto/ubuntu-cve-tracker:oval-meta-kernel into ubuntu-cve-tracker:master
- Git
- lp:~ebarretto/ubuntu-cve-tracker
- oval-meta-kernel
- Merge into 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) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Security Team | Pending | ||
Review via email: mp+437896@code.launchpad.net |
Commit message
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 : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/scripts/generate-oval b/scripts/generate-oval | |||
2 | index 849ef82..b6dd88e 100755 | |||
3 | --- a/scripts/generate-oval | |||
4 | +++ b/scripts/generate-oval | |||
5 | @@ -37,7 +37,7 @@ import tempfile | |||
6 | 37 | 37 | ||
7 | 38 | import apt_pkg | 38 | import apt_pkg |
8 | 39 | 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) | 39 | 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) |
10 | 40 | from kernel_lib import (meta_kernels, kernel_package_abi, kernel_package_version) | 40 | from kernel_lib import meta_kernels |
11 | 41 | import oval_lib | 41 | import oval_lib |
12 | 42 | import lpl_common | 42 | import lpl_common |
13 | 43 | 43 | ||
14 | @@ -365,30 +365,6 @@ def parse_cve_file(filepath, cache, pkg_filter=None): | |||
15 | 365 | rel for rel in packages[package]['Releases'] | 365 | rel for rel in packages[package]['Releases'] |
16 | 366 | if packages[package]['Releases'][rel]['status'] != 'not-applicable' | 366 | if packages[package]['Releases'][rel]['status'] != 'not-applicable' |
17 | 367 | ]: | 367 | ]: |
18 | 368 | # add meta package | ||
19 | 369 | # handle meta package of subprojects without needing to have them in kernel_lib | ||
20 | 370 | progenitor = release_progenitor(release) | ||
21 | 371 | if progenitor: | ||
22 | 372 | meta_pkg = meta_kernels.get_meta(progenitor, package, quiet=(debug_level < 1)) | ||
23 | 373 | else: | ||
24 | 374 | meta_pkg = meta_kernels.get_meta(release, package, quiet=(debug_level < 1)) | ||
25 | 375 | if meta_pkg: | ||
26 | 376 | if meta_pkg not in packages: | ||
27 | 377 | packages[meta_pkg] = { | ||
28 | 378 | 'Priority': packages[package]['Priority'], | ||
29 | 379 | 'Tags': packages[package]['Tags'], | ||
30 | 380 | 'Releases': {} | ||
31 | 381 | } | ||
32 | 382 | if release not in packages[meta_pkg]['Releases']: | ||
33 | 383 | kernel_status = packages[package]['Releases'][release] | ||
34 | 384 | # kernel meta packages have a different versioning | ||
35 | 385 | # scheme derived from the kernel version + kernel abi | ||
36 | 386 | meta_version = None | ||
37 | 387 | if 'fix-version' in kernel_status: | ||
38 | 388 | meta_version = '%s.%s' % (kernel_package_version(kernel_status['fix-version']), | ||
39 | 389 | kernel_package_abi(kernel_status['fix-version'])) | ||
40 | 390 | packages[meta_pkg]['Releases'][release] = \ | ||
41 | 391 | duplicate_package_status(release, meta_pkg, kernel_status, cache, override_version=meta_version) | ||
42 | 392 | # add signed package | 368 | # add signed package |
43 | 393 | # handle signed package of subprojects without needing to have them in kernel_lib | 369 | # handle signed package of subprojects without needing to have them in kernel_lib |
44 | 394 | progenitor = release_progenitor(release) | 370 | progenitor = release_progenitor(release) |
45 | diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py | |||
46 | index 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 | 79 | 79 | ||
51 | 80 | return instruction | 80 | return instruction |
52 | 81 | 81 | ||
53 | 82 | def is_kernel_binaries(binaries): | ||
54 | 83 | reg = re.compile('linux-image-.*') | ||
55 | 84 | if any(filter(reg.match, binaries)): | ||
56 | 85 | return True | ||
57 | 86 | return False | ||
58 | 87 | |||
59 | 88 | |||
60 | 89 | """ Using the following kernel uname, we can understand its format: | ||
61 | 90 | uname -r -> 5.4.0-1059-generic | ||
62 | 91 | MAJOR_VERSION="5.4.0" | ||
63 | 92 | ABI="1059" | ||
64 | 93 | FLAVOUR="generic" | ||
65 | 94 | """ | ||
66 | 95 | def process_kernel_binaries(binaries, oval_format): | ||
67 | 96 | packages = ' '.join(binaries) | ||
68 | 97 | parts = re.findall('linux-image-[a-z]*-?([\d|\.]+-)\d+(-[\w|-]+)', packages) | ||
69 | 98 | if parts: | ||
70 | 99 | values = set(map(lambda x: x[0], parts)) | ||
71 | 100 | version = ''.join(values) | ||
72 | 101 | values = set(map(lambda x: x[1], parts)) | ||
73 | 102 | flavours = '|'.join(values) | ||
74 | 103 | regex = version + '\d+(' + flavours + ')' | ||
75 | 104 | if oval_format == 'oci': | ||
76 | 105 | regex = 'linux-image-(?:unsigned-)?' + regex | ||
77 | 106 | return regex | ||
78 | 107 | |||
79 | 108 | return None | ||
80 | 109 | |||
81 | 110 | |||
82 | 82 | class OvalGenerator: | 111 | class OvalGenerator: |
83 | 83 | supported_oval_elements = ('definition', 'test', 'object', 'state', | 112 | supported_oval_elements = ('definition', 'test', 'object', 'state', |
84 | 84 | 'variable') | 113 | 'variable') |
85 | @@ -138,7 +167,7 @@ class OvalGenerator: | |||
86 | 138 | 'id_base': id_base + len(test_refs), | 167 | 'id_base': id_base + len(test_refs), |
87 | 139 | 'source-note': header['Source-note'] | 168 | 'source-note': header['Source-note'] |
88 | 140 | } | 169 | } |
90 | 141 | if package.startswith('linux') and self.oval_format == 'dpkg' and pkg['fix-version']: | 170 | if is_kernel_binaries(pkg['binaries']) and pkg['fix-version']: |
91 | 142 | test_ref = self.get_running_kernel_testref(pkg) | 171 | test_ref = self.get_running_kernel_testref(pkg) |
92 | 143 | if test_ref: | 172 | if test_ref: |
93 | 144 | test_refs = test_refs + test_ref | 173 | test_refs = test_refs + test_ref |
94 | @@ -277,25 +306,44 @@ class OvalGenerator: | |||
95 | 277 | </definition>\n""".format(**mapping)) | 306 | </definition>\n""".format(**mapping)) |
96 | 278 | 307 | ||
97 | 279 | def get_running_kernel_testref(self, package): | 308 | def get_running_kernel_testref(self, package): |
117 | 280 | """ Using the following kernel uname, we can understand its format: | 309 | uname_regex = process_kernel_binaries(package['binaries'], self.oval_format) |
118 | 281 | uname -r -> 5.4.0-1059-generic | 310 | if uname_regex: |
119 | 282 | MAJOR_VERSION="5.4.0" | 311 | if self.oval_format == 'dpkg': |
120 | 283 | ABI="1059" | 312 | (var_id, var_id_2) = self.get_running_kernel_variable_id( |
121 | 284 | FLAVOUR="generic" | 313 | uname_regex, |
122 | 285 | """ | 314 | package['id_base'], |
123 | 286 | for pkg in package['binaries']: | 315 | package['fix-version']) |
124 | 287 | uname = re.search('linux-image-[a-z]*-?([\d|\.]+-)(\d+)(-[\w|-]+)', pkg) | 316 | (ste_id, ste_id_2) = self.get_running_kernel_state_id( |
125 | 288 | if uname: | 317 | uname_regex, |
126 | 289 | uname_regex = uname.group(1) + '\d{' + str(len(uname.group(2))) + '}' + uname.group(3) | 318 | package['id_base'], |
127 | 290 | (var_id, var_id_2) = self.get_running_kernel_variable_id(uname_regex, package['id_base'], package['fix-version']) | 319 | var_id) |
128 | 291 | (ste_id, ste_id_2) = self.get_running_kernel_state_id(uname_regex, package['id_base'], var_id) | 320 | (obj_id, obj_id_2) = self.get_running_kernel_object_id( |
129 | 292 | (obj_id, obj_id_2) = self.get_running_kernel_object_id(package['id_base'], var_id_2) | 321 | package['id_base'], var_id_2) |
130 | 293 | (test_id, test_id_2) = self.get_running_kernel_test_id(uname_regex, package['id_base'], package['name'], | 322 | (test_id, test_id_2) = self.get_running_kernel_test_id( |
131 | 294 | obj_id, ste_id, obj_id_2, ste_id_2) | 323 | uname_regex, package['id_base'], package['name'], |
132 | 295 | return [{'id': test_id, 'comment': 'Is kernel {0} running'.format(package['name']), | 324 | obj_id, ste_id, obj_id_2, ste_id_2) |
133 | 296 | 'kernel': uname_regex, 'var_id': var_id}, {'id': test_id_2, 'comment': 'kernel version comparison', 'kernelobj': True}] | 325 | return [{'id': test_id, |
134 | 297 | 326 | 'comment': 'Is kernel {0} running'.format(package['name']), | |
135 | 298 | return None | 327 | 'kernel': uname_regex, 'var_id': var_id}, |
136 | 328 | {'id': test_id_2, 'comment': 'kernel version comparison', | ||
137 | 329 | 'kernelobj': True}] | ||
138 | 330 | else: # OCI | ||
139 | 331 | object_id = self.get_package_object_id(package['name'], | ||
140 | 332 | uname_regex, | ||
141 | 333 | package['id_base']) | ||
142 | 334 | state_id = self.get_package_version_state_id(package['id_base'], | ||
143 | 335 | package['fix-version']) | ||
144 | 336 | test_title = "Does the '{0}' package exist and is the version less than '{1}'?".format(package['name'], | ||
145 | 337 | package['fix-version']) | ||
146 | 338 | test_id = self.get_package_test_id(package['name'], | ||
147 | 339 | package['id_base'], | ||
148 | 340 | test_title, | ||
149 | 341 | object_id, | ||
150 | 342 | state_id) | ||
151 | 343 | package['note'] = package['name'] + package['note'] | ||
152 | 344 | return [{'id': test_id, 'comment': package['note']}] | ||
153 | 345 | |||
154 | 346 | return None | ||
155 | 299 | 347 | ||
156 | 300 | def get_oval_test_for_package(self, package): | 348 | def get_oval_test_for_package(self, package): |
157 | 301 | """ create OVAL test and dependent objects for this package status | 349 | """ create OVAL test and dependent objects for this package status |
158 | @@ -1314,25 +1362,22 @@ class OvalGeneratorUSN(): | |||
159 | 1314 | return version_map | 1362 | return version_map |
160 | 1315 | 1363 | ||
161 | 1316 | def get_testref(self, version, pkgs, testref_id): | 1364 | def get_testref(self, version, pkgs, testref_id): |
172 | 1317 | reg = re.compile('linux-image-.*') | 1365 | if is_kernel_binaries(pkgs): |
173 | 1318 | if any(filter(reg.match, pkgs)) and self.oval_format == 'dpkg': | 1366 | uname_regex = process_kernel_binaries(pkgs, self.oval_format) |
174 | 1319 | for pkg in pkgs: | 1367 | if uname_regex: |
175 | 1320 | uname = re.search('linux-image-[a-z]*-?([\d|\.]+-)(\d+)(-[\w|-]+)', pkg) | 1368 | if self.oval_format == 'dpkg': |
166 | 1321 | if uname: | ||
167 | 1322 | # transform pkgs list into string to make it easy to | ||
168 | 1323 | # get all flavours at once in a list | ||
169 | 1324 | packages = ' '.join(pkgs) | ||
170 | 1325 | flavours = set(re.findall('linux-image-[a-z]*-?[\d|\.]+-\d+-([\w|-]+)', packages)) | ||
171 | 1326 | name = uname.group(1) + '\d{' + str(len(uname.group(2))) + '}-(' + '|'.join(flavours) + ')' | ||
176 | 1327 | new_id = '{0}0'.format(testref_id) | 1369 | new_id = '{0}0'.format(testref_id) |
177 | 1328 | new_id_2 = '{0}0'.format(testref_id + 1) | 1370 | new_id_2 = '{0}0'.format(testref_id + 1) |
178 | 1329 | # kernel has two test_ref: | 1371 | # kernel has two test_ref: |
179 | 1330 | # 1. check if running kernel is of same version and flavour as patched | 1372 | # 1. check if running kernel is of same version and flavour as patched |
180 | 1331 | # 2. check if running kernel is less than patched kernel | 1373 | # 2. check if running kernel is less than patched kernel |
183 | 1332 | return ({'version': version, 'pkgs': [uname.group(0)], | 1374 | return ({'version': version, 'pkgs': pkgs, |
184 | 1333 | 'testref_id': new_id, 'kernel': name}, | 1375 | 'testref_id': new_id, 'kernel': uname_regex}, |
185 | 1334 | {'version': version, 'pkgs': pkgs, | 1376 | {'version': version, 'pkgs': pkgs, |
186 | 1335 | 'testref_id': new_id_2, 'kernelobj': new_id}) | 1377 | 'testref_id': new_id_2, 'kernelobj': new_id}) |
187 | 1378 | else: | ||
188 | 1379 | new_id = '{0}0'.format(testref_id) | ||
189 | 1380 | return({'version': version, 'pkgs': [uname_regex], 'testref_id': new_id}, None) | ||
190 | 1336 | 1381 | ||
191 | 1337 | return (None, None) | 1382 | return (None, None) |
192 | 1338 | 1383 |
LGTM!