Merge ~litios/ubuntu-cve-tracker:oval/fix_broken_criteria into ubuntu-cve-tracker:master
- Git
- lp:~litios/ubuntu-cve-tracker
- oval/fix_broken_criteria
- Merge into master
Proposed by
David Fernandez Gonzalez
Status: | Merged |
---|---|
Merge reported by: | David Fernandez Gonzalez |
Merged at revision: | 2ce9e012bd027389b5bf836a2c7e4fc000218f0f |
Proposed branch: | ~litios/ubuntu-cve-tracker:oval/fix_broken_criteria |
Merge into: | ubuntu-cve-tracker:master |
Diff against target: |
173 lines (+42/-22) 1 file modified
scripts/oval_lib.py (+42/-22) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paulo Flabiano Smorigo | Approve | ||
Eduardo Barretto | Approve | ||
Review via email: mp+457529@code.launchpad.net |
Commit message
Description of the change
This PR fixes several issues:
1. Prevent empty CVEs from being created when the affected packages have no valid binaries.
2. Properly set parent release priorities. A bug occurred where the status wasn't set correctly, making the results unpredictable.
3. Set the right version and status when there are parent releases involved.
1. If the status is vulnerable, use the top release with the latest available binaries.
2. If the status is fixed, find the parent in which it was fixed and use that.
To post a comment you must log in.
Revision history for this message
David Fernandez Gonzalez (litios) wrote : | # |
Revision history for this message
Eduardo Barretto (ebarretto) wrote : | # |
lgtm, thanks for handling/
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/scripts/oval_lib.py b/scripts/oval_lib.py | |||
2 | index f0c89fc..489200e 100644 | |||
3 | --- a/scripts/oval_lib.py | |||
4 | +++ b/scripts/oval_lib.py | |||
5 | @@ -311,15 +311,24 @@ class CVE: | |||
6 | 311 | continue | 311 | continue |
7 | 312 | 312 | ||
8 | 313 | if pkg.name not in pkg_rel: | 313 | if pkg.name not in pkg_rel: |
13 | 314 | pkg_rel[pkg.name] = pkg.rel | 314 | pkg_rel[pkg.name] = pkg |
14 | 315 | elif releases.index(pkg.rel) < releases.index(pkg_rel[pkg.name]): | 315 | else: |
15 | 316 | pkg_rel[pkg.name] = pkg.rel | 316 | pkg_rel_entry = self.pkg_rel_entries[str(pkg)] |
16 | 317 | 317 | curr_pkg_rel_entry = self.pkg_rel_entries[str(pkg_rel[pkg.name])] | |
17 | 318 | if curr_pkg_rel_entry.status == 'fixed': | ||
18 | 319 | priority = releases.index(pkg.rel) > releases.index(pkg_rel[pkg.name].rel) and \ | ||
19 | 320 | pkg_rel_entry.fixed_version in pkg.versions_binaries | ||
20 | 321 | else: | ||
21 | 322 | priority = releases.index(pkg.rel) < releases.index(pkg_rel[pkg.name].rel) | ||
22 | 323 | |||
23 | 324 | if priority: | ||
24 | 325 | pkg_rel[pkg.name] = pkg | ||
25 | 326 | |||
26 | 318 | for pkg in self.pkgs: | 327 | for pkg in self.pkgs: |
27 | 319 | if self.pkg_rel_entries[str(pkg)].is_not_applicable(): | 328 | if self.pkg_rel_entries[str(pkg)].is_not_applicable(): |
28 | 320 | continue | 329 | continue |
29 | 321 | 330 | ||
31 | 322 | if pkg.name in pkg_rel and pkg_rel[pkg.name] == pkg.rel: | 331 | if pkg.name in pkg_rel and pkg_rel[pkg.name].rel == pkg.rel: |
32 | 323 | pkgs.append(pkg) | 332 | pkgs.append(pkg) |
33 | 324 | 333 | ||
34 | 325 | return pkgs | 334 | return pkgs |
35 | @@ -433,11 +442,13 @@ class Package: | |||
36 | 433 | def get_binaries(self, source_version, binary_version): | 442 | def get_binaries(self, source_version, binary_version): |
37 | 434 | if not self.versions_binaries: return {} | 443 | if not self.versions_binaries: return {} |
38 | 435 | if source_version not in self.versions_binaries: | 444 | if source_version not in self.versions_binaries: |
39 | 436 | if len(self.versions_binaries[self.earliest_version]) != 1: | ||
40 | 437 | print(f"WARN: Version {source_version} doesn't exist yet the package {self.name} has different versions for the binaries") | ||
41 | 438 | |||
42 | 439 | version_binaries = self.versions_binaries[self.earliest_version] | 445 | version_binaries = self.versions_binaries[self.earliest_version] |
44 | 440 | return version_binaries[self.get_binary_versions(self.earliest_version)[0]] | 446 | if len(version_binaries) > 1: |
45 | 447 | print(f"WARN: Version {source_version} doesn't exist yet the package {self.name} has different versions for the binaries") | ||
46 | 448 | elif len(version_binaries) == 0: | ||
47 | 449 | return [] | ||
48 | 450 | binary_versions = self.get_binary_versions(self.earliest_version) | ||
49 | 451 | return version_binaries[binary_versions[0]] | ||
50 | 441 | return self.versions_binaries[source_version][binary_version] | 452 | return self.versions_binaries[source_version][binary_version] |
51 | 442 | 453 | ||
52 | 443 | def __str__(self) -> str: | 454 | def __str__(self) -> str: |
53 | @@ -483,12 +494,13 @@ class OvalGenerator: | |||
54 | 483 | self.release_codename = cve_lib.release_progenitor(self.release) if cve_lib.release_progenitor(self.release) else self.release.replace('/', '_') | 494 | self.release_codename = cve_lib.release_progenitor(self.release) if cve_lib.release_progenitor(self.release) else self.release.replace('/', '_') |
55 | 484 | self.release_name = cve_lib.release_name(self.release) | 495 | self.release_name = cve_lib.release_name(self.release) |
56 | 485 | 496 | ||
58 | 486 | self.parent_releases = set() | 497 | self.parent_releases = list() |
59 | 487 | current_release = self.release | 498 | current_release = self.release |
60 | 488 | while(cve_lib.release_parent(current_release)): | 499 | while(cve_lib.release_parent(current_release)): |
61 | 489 | current_release = cve_lib.release_parent(current_release) | 500 | current_release = cve_lib.release_parent(current_release) |
64 | 490 | if current_release != self.release: | 501 | if current_release != self.release and \ |
65 | 491 | self.parent_releases.add(current_release) | 502 | current_release not in self.parent_releases: |
66 | 503 | self.parent_releases.append(current_release) | ||
67 | 492 | 504 | ||
68 | 493 | self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename) | 505 | self.ns = 'oval:com.ubuntu.{0}'.format(self.release_codename) |
69 | 494 | self.id = 100 | 506 | self.id = 100 |
70 | @@ -1441,7 +1453,7 @@ class OvalGeneratorPkg(OvalGenerator): | |||
71 | 1441 | self._increase_id(is_definition=True) | 1453 | self._increase_id(is_definition=True) |
72 | 1442 | 1454 | ||
73 | 1443 | all_pkgs = dict() | 1455 | all_pkgs = dict() |
75 | 1444 | for parent_release in list(self.parent_releases)[::-1]: | 1456 | for parent_release in self.parent_releases[::-1]: |
76 | 1445 | all_pkgs.update(self.packages[parent_release]) | 1457 | all_pkgs.update(self.packages[parent_release]) |
77 | 1446 | 1458 | ||
78 | 1447 | all_pkgs.update(self.packages[self.release]) | 1459 | all_pkgs.update(self.packages[self.release]) |
79 | @@ -1556,16 +1568,18 @@ class OvalGeneratorCVE(OvalGenerator): | |||
80 | 1556 | 1568 | ||
81 | 1557 | return instruction | 1569 | return instruction |
82 | 1558 | 1570 | ||
84 | 1559 | def _populate_pkg(self, cve: CVE, package: Package, root_element, main_criteria, cache, fixed_versions) -> None: | 1571 | def _populate_pkg(self, cve: CVE, package: Package, root_element, main_criteria, cache, fixed_versions) -> bool: |
85 | 1560 | tests = root_element.find("tests") | 1572 | tests = root_element.find("tests") |
86 | 1561 | objects = root_element.find("objects") | 1573 | objects = root_element.find("objects") |
87 | 1562 | variables = root_element.find("variables") | 1574 | variables = root_element.find("variables") |
88 | 1563 | states = root_element.find("states") | 1575 | states = root_element.find("states") |
89 | 1564 | pkg_rel_entry = cve.pkg_rel_entries[str(package)] | 1576 | pkg_rel_entry = cve.pkg_rel_entries[str(package)] |
90 | 1577 | added = False | ||
91 | 1565 | 1578 | ||
92 | 1566 | source_version = package.get_version_to_check(pkg_rel_entry.fixed_version) | 1579 | source_version = package.get_version_to_check(pkg_rel_entry.fixed_version) |
93 | 1567 | for binary_version in package.get_binary_versions(source_version): | 1580 | for binary_version in package.get_binary_versions(source_version): |
94 | 1568 | binaries = package.get_binaries(source_version, binary_version) | 1581 | binaries = package.get_binaries(source_version, binary_version) |
95 | 1582 | if not binaries: continue | ||
96 | 1569 | cache_entry = f'{package.name}-{binary_version}' | 1583 | cache_entry = f'{package.name}-{binary_version}' |
97 | 1570 | 1584 | ||
98 | 1571 | cache.setdefault(cache_entry, dict(bin_id=None, def_id=None)) | 1585 | cache.setdefault(cache_entry, dict(bin_id=None, def_id=None)) |
99 | @@ -1578,6 +1592,7 @@ class OvalGeneratorCVE(OvalGenerator): | |||
100 | 1578 | cache_entry_bin = cache_entry | 1592 | cache_entry_bin = cache_entry |
101 | 1579 | 1593 | ||
102 | 1580 | if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only: | 1594 | if pkg_rel_entry.status == 'vulnerable' and not self.fixed_only: |
103 | 1595 | added = True | ||
104 | 1581 | if not cache_entry in cache or not cache[cache_entry]['def_id']: | 1596 | if not cache_entry in cache or not cache[cache_entry]['def_id']: |
105 | 1582 | self._add_criterion(self.definition_id, pkg_rel_entry, cve, main_criteria) | 1597 | self._add_criterion(self.definition_id, pkg_rel_entry, cve, main_criteria) |
106 | 1583 | 1598 | ||
107 | @@ -1594,6 +1609,7 @@ class OvalGeneratorCVE(OvalGenerator): | |||
108 | 1594 | else: | 1609 | else: |
109 | 1595 | self._add_criterion(cache[cache_entry]['def_id'], pkg_rel_entry, cve, main_criteria) | 1610 | self._add_criterion(cache[cache_entry]['def_id'], pkg_rel_entry, cve, main_criteria) |
110 | 1596 | elif pkg_rel_entry.status == 'fixed': | 1611 | elif pkg_rel_entry.status == 'fixed': |
111 | 1612 | added = True | ||
112 | 1597 | if binary_version in fixed_versions: | 1613 | if binary_version in fixed_versions: |
113 | 1598 | self._add_criterion(fixed_versions[binary_version], pkg_rel_entry, cve, main_criteria) | 1614 | self._add_criterion(fixed_versions[binary_version], pkg_rel_entry, cve, main_criteria) |
114 | 1599 | else: | 1615 | else: |
115 | @@ -1611,6 +1627,8 @@ class OvalGeneratorCVE(OvalGenerator): | |||
116 | 1611 | fixed_versions[binary_version] = self.definition_id | 1627 | fixed_versions[binary_version] = self.definition_id |
117 | 1612 | self._increase_id(is_definition=False) | 1628 | self._increase_id(is_definition=False) |
118 | 1613 | 1629 | ||
119 | 1630 | return added | ||
120 | 1631 | |||
121 | 1614 | def _populate_kernel_pkg(self, cve: CVE, package: Package, root_element, main_criteria, running_kernel_id, cache, fixed_versions) -> None: | 1632 | def _populate_kernel_pkg(self, cve: CVE, package: Package, root_element, main_criteria, running_kernel_id, cache, fixed_versions) -> None: |
122 | 1615 | # Kernel binaries have all same version | 1633 | # Kernel binaries have all same version |
123 | 1616 | version = package.get_latest_version() | 1634 | version = package.get_latest_version() |
124 | @@ -1636,27 +1654,29 @@ class OvalGeneratorCVE(OvalGenerator): | |||
125 | 1636 | 1654 | ||
126 | 1637 | def _generate_elements_from_cve(self, cve, supported_releases, root_element, running_kernel_id, pkg_cache, fixed_versions) -> None: | 1655 | def _generate_elements_from_cve(self, cve, supported_releases, root_element, running_kernel_id, pkg_cache, fixed_versions) -> None: |
127 | 1638 | if not cve.pkgs: return | 1656 | if not cve.pkgs: return |
129 | 1639 | added = False | 1657 | cve_added = False |
130 | 1640 | definition_element = self._generate_definition_object(cve) | 1658 | definition_element = self._generate_definition_object(cve) |
131 | 1641 | instructions = '' | 1659 | instructions = '' |
132 | 1642 | pkgs = cve.get_pkgs(supported_releases) | 1660 | pkgs = cve.get_pkgs(supported_releases) |
133 | 1643 | for pkg in pkgs: | 1661 | for pkg in pkgs: |
134 | 1662 | pkg_added = False | ||
135 | 1644 | if not pkg.versions_binaries: continue | 1663 | if not pkg.versions_binaries: continue |
136 | 1645 | if not pkg.get_binary_versions(next(iter(pkg.versions_binaries))): continue | ||
137 | 1646 | if self._ignore_source_package(pkg.name): continue | 1664 | if self._ignore_source_package(pkg.name): continue |
138 | 1647 | 1665 | ||
139 | 1648 | added = True | ||
140 | 1649 | pkg_rel_entry = cve.pkg_rel_entries[str(pkg)] | 1666 | pkg_rel_entry = cve.pkg_rel_entries[str(pkg)] |
141 | 1650 | if pkg.is_kernel_pkg and self.oval_format != 'oci': | 1667 | if pkg.is_kernel_pkg and self.oval_format != 'oci': |
142 | 1651 | self._populate_kernel_pkg(cve, pkg, root_element, definition_element, running_kernel_id, pkg_cache, fixed_versions) | 1668 | self._populate_kernel_pkg(cve, pkg, root_element, definition_element, running_kernel_id, pkg_cache, fixed_versions) |
143 | 1669 | pkg_added = True | ||
144 | 1652 | else: | 1670 | else: |
146 | 1653 | self._populate_pkg(cve, pkg, root_element, definition_element, pkg_cache, fixed_versions) | 1671 | pkg_added = self._populate_pkg(cve, pkg, root_element, definition_element, pkg_cache, fixed_versions) |
147 | 1654 | 1672 | ||
149 | 1655 | if pkg_rel_entry.status == 'fixed' and pkg.versions_binaries: | 1673 | if pkg_rel_entry.status == 'fixed' and pkg_added: |
150 | 1656 | product_description = cve_lib.get_subproject_description(pkg_rel_entry.release) | 1674 | product_description = cve_lib.get_subproject_description(pkg_rel_entry.release) |
151 | 1657 | instructions = self.prepare_instructions(instructions, cve, product_description, pkg, pkg_rel_entry.fixed_version) | 1675 | instructions = self.prepare_instructions(instructions, cve, product_description, pkg, pkg_rel_entry.fixed_version) |
152 | 1676 | |||
153 | 1677 | cve_added = cve_added | pkg_added | ||
154 | 1658 | 1678 | ||
156 | 1659 | if added: | 1679 | if cve_added: |
157 | 1660 | definitions = root_element.find("definitions") | 1680 | definitions = root_element.find("definitions") |
158 | 1661 | metadata = definition_element.find('metadata') | 1681 | metadata = definition_element.find('metadata') |
159 | 1662 | metadata.find('description').text = metadata.find('description').text + instructions | 1682 | metadata.find('description').text = metadata.find('description').text + instructions |
160 | @@ -1681,11 +1701,11 @@ class OvalGeneratorCVE(OvalGenerator): | |||
161 | 1681 | 1701 | ||
162 | 1682 | pkg_cache = {} | 1702 | pkg_cache = {} |
163 | 1683 | fixed_versions = {} | 1703 | fixed_versions = {} |
165 | 1684 | accepted_releases = list(self.parent_releases) | 1704 | accepted_releases = self.parent_releases.copy() |
166 | 1685 | accepted_releases.insert(0, self.release) | 1705 | accepted_releases.insert(0, self.release) |
167 | 1686 | 1706 | ||
168 | 1687 | all_cves = self.cves[self.release] | 1707 | all_cves = self.cves[self.release] |
170 | 1688 | for parent_release in list(self.parent_releases): | 1708 | for parent_release in self.parent_releases: |
171 | 1689 | for cve in self.cves[parent_release]: | 1709 | for cve in self.cves[parent_release]: |
172 | 1690 | if cve not in all_cves: | 1710 | if cve not in all_cves: |
173 | 1691 | all_cves[cve] = self.cves[parent_release][cve] | 1711 | all_cves[cve] = self.cves[parent_release][cve] |
Diffs:
* Jammy: https:/ /pastebin. canonical. com/p/NTjzD4Fkj j/ (None) /pastebin. canonical. com/p/h5nvD5RWn P/ (None) /pastebin. canonical. com/p/NVXXRq7Hd 3/ (Empty CVE gone) /pastebin. canonical. com/p/r4jfy6nhn c/ (Emtpy CVE gone)
* Jammy OCI: https:/
* Bionic: https:/
* Bionic OCI: https:/
* ESM-apps Xenial: Too long for pastebin (Many esm-apps/xenial -> xenial, affects kernel too)
- Results diff: (None)