diff options
-rw-r--r-- | meta/classes/cve-check.bbclass | 12 | ||||
-rw-r--r-- | meta/lib/oe/cve_check.py | 40 | ||||
-rw-r--r-- | meta/lib/oeqa/selftest/cases/cve_check.py | 11 |
3 files changed, 39 insertions, 24 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index 646cc879dd..ed86403b6b 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass | |||
@@ -53,6 +53,9 @@ CVE_CHECK_PN_WHITELIST ?= "" | |||
53 | # | 53 | # |
54 | CVE_CHECK_WHITELIST ?= "" | 54 | CVE_CHECK_WHITELIST ?= "" |
55 | 55 | ||
56 | # set to "alphabetical" for version using single alphabetical character as increament release | ||
57 | CVE_VERSION_SUFFIX ??= "" | ||
58 | |||
56 | python cve_save_summary_handler () { | 59 | python cve_save_summary_handler () { |
57 | import shutil | 60 | import shutil |
58 | import datetime | 61 | import datetime |
@@ -210,6 +213,7 @@ def check_cves(d, patched_cves): | |||
210 | 213 | ||
211 | pn = d.getVar("PN") | 214 | pn = d.getVar("PN") |
212 | real_pv = d.getVar("PV") | 215 | real_pv = d.getVar("PV") |
216 | suffix = d.getVar("CVE_VERSION_SUFFIX") | ||
213 | 217 | ||
214 | cves_unpatched = [] | 218 | cves_unpatched = [] |
215 | # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) | 219 | # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) |
@@ -263,8 +267,8 @@ def check_cves(d, patched_cves): | |||
263 | else: | 267 | else: |
264 | if operator_start: | 268 | if operator_start: |
265 | try: | 269 | try: |
266 | vulnerable_start = (operator_start == '>=' and Version(pv) >= Version(version_start)) | 270 | vulnerable_start = (operator_start == '>=' and Version(pv,suffix) >= Version(version_start,suffix)) |
267 | vulnerable_start |= (operator_start == '>' and Version(pv) > Version(version_start)) | 271 | vulnerable_start |= (operator_start == '>' and Version(pv,suffix) > Version(version_start,suffix)) |
268 | except: | 272 | except: |
269 | bb.warn("%s: Failed to compare %s %s %s for %s" % | 273 | bb.warn("%s: Failed to compare %s %s %s for %s" % |
270 | (product, pv, operator_start, version_start, cve)) | 274 | (product, pv, operator_start, version_start, cve)) |
@@ -274,8 +278,8 @@ def check_cves(d, patched_cves): | |||
274 | 278 | ||
275 | if operator_end: | 279 | if operator_end: |
276 | try: | 280 | try: |
277 | vulnerable_end = (operator_end == '<=' and Version(pv) <= Version(version_end) ) | 281 | vulnerable_end = (operator_end == '<=' and Version(pv,suffix) <= Version(version_end,suffix) ) |
278 | vulnerable_end |= (operator_end == '<' and Version(pv) < Version(version_end) ) | 282 | vulnerable_end |= (operator_end == '<' and Version(pv,suffix) < Version(version_end,suffix) ) |
279 | except: | 283 | except: |
280 | bb.warn("%s: Failed to compare %s %s %s for %s" % | 284 | bb.warn("%s: Failed to compare %s %s %s for %s" % |
281 | (product, pv, operator_end, version_end, cve)) | 285 | (product, pv, operator_end, version_end, cve)) |
diff --git a/meta/lib/oe/cve_check.py b/meta/lib/oe/cve_check.py index ec48a3f829..ce755f940a 100644 --- a/meta/lib/oe/cve_check.py +++ b/meta/lib/oe/cve_check.py | |||
@@ -1,58 +1,60 @@ | |||
1 | import collections | 1 | import collections |
2 | import re | 2 | import re |
3 | import itertools | 3 | import itertools |
4 | import functools | ||
4 | 5 | ||
5 | _Version = collections.namedtuple( | 6 | _Version = collections.namedtuple( |
6 | "_Version", ["release", "pre_l", "pre_v"] | 7 | "_Version", ["release", "patch_l", "pre_l", "pre_v"] |
7 | ) | 8 | ) |
8 | 9 | ||
10 | @functools.total_ordering | ||
9 | class Version(): | 11 | class Version(): |
10 | _version_pattern = r"""v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" | 12 | |
11 | _regex = re.compile(r"^\s*" + _version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE) | 13 | def __init__(self, version, suffix=None): |
12 | def __init__(self, version): | 14 | if str(suffix) == "alphabetical": |
13 | match = self._regex.search(version) | 15 | version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<patch>[-_\.]?(?P<patch_l>[a-z]))?(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" |
16 | else: | ||
17 | version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" | ||
18 | regex = re.compile(r"^\s*" + version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE) | ||
19 | |||
20 | match = regex.search(version) | ||
14 | if not match: | 21 | if not match: |
15 | raise Exception("Invalid version: '{0}'".format(version)) | 22 | raise Exception("Invalid version: '{0}'".format(version)) |
16 | 23 | ||
17 | self._version = _Version( | 24 | self._version = _Version( |
18 | release=tuple(int(i) for i in match.group("release").replace("-",".").split(".")), | 25 | release=tuple(int(i) for i in match.group("release").replace("-",".").split(".")), |
26 | patch_l=match.group("patch_l") if str(suffix) == "alphabetical" and match.group("patch_l") else "", | ||
19 | pre_l=match.group("pre_l"), | 27 | pre_l=match.group("pre_l"), |
20 | pre_v=match.group("pre_v") | 28 | pre_v=match.group("pre_v") |
21 | ) | 29 | ) |
22 | 30 | ||
23 | self._key = _cmpkey( | 31 | self._key = _cmpkey( |
24 | self._version.release, | 32 | self._version.release, |
33 | self._version.patch_l, | ||
25 | self._version.pre_l, | 34 | self._version.pre_l, |
26 | self._version.pre_v | 35 | self._version.pre_v |
27 | ) | 36 | ) |
28 | 37 | ||
29 | def __le__(self, other): | 38 | def __eq__(self, other): |
30 | if not isinstance(other, Version): | ||
31 | return NotImplemented | ||
32 | return self._key <= other._key | ||
33 | |||
34 | def __lt__(self, other): | ||
35 | if not isinstance(other, Version): | 39 | if not isinstance(other, Version): |
36 | return NotImplemented | 40 | return NotImplemented |
37 | return self._key < other._key | 41 | return self._key == other._key |
38 | |||
39 | def __ge__(self, other): | ||
40 | if not isinstance(other, Version): | ||
41 | return NotImplemented | ||
42 | return self._key >= other._key | ||
43 | 42 | ||
44 | def __gt__(self, other): | 43 | def __gt__(self, other): |
45 | if not isinstance(other, Version): | 44 | if not isinstance(other, Version): |
46 | return NotImplemented | 45 | return NotImplemented |
47 | return self._key > other._key | 46 | return self._key > other._key |
48 | 47 | ||
49 | def _cmpkey(release, pre_l, pre_v): | 48 | def _cmpkey(release, patch_l, pre_l, pre_v): |
50 | # remove leading 0 | 49 | # remove leading 0 |
51 | _release = tuple( | 50 | _release = tuple( |
52 | reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) | 51 | reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) |
53 | ) | 52 | ) |
53 | |||
54 | _patch = patch_l.upper() | ||
55 | |||
54 | if pre_l is None and pre_v is None: | 56 | if pre_l is None and pre_v is None: |
55 | _pre = float('inf') | 57 | _pre = float('inf') |
56 | else: | 58 | else: |
57 | _pre = float(pre_v) if pre_v else float('-inf') | 59 | _pre = float(pre_v) if pre_v else float('-inf') |
58 | return _release, _pre | 60 | return _release, _patch, _pre |
diff --git a/meta/lib/oeqa/selftest/cases/cve_check.py b/meta/lib/oeqa/selftest/cases/cve_check.py index 35e2b29a9a..3f343a2841 100644 --- a/meta/lib/oeqa/selftest/cases/cve_check.py +++ b/meta/lib/oeqa/selftest/cases/cve_check.py | |||
@@ -23,5 +23,14 @@ class CVECheck(OESelftestTestCase): | |||
23 | self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'") | 23 | self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'") |
24 | 24 | ||
25 | # ignore "p1" and "p2", so these should be equal | 25 | # ignore "p1" and "p2", so these should be equal |
26 | result = Version("1.0p2") <= Version("1.0p1") and Version("1.0p2") >= Version("1.0p1") | 26 | result = Version("1.0p2") == Version("1.0p1") |
27 | self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'") | 27 | self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'") |
28 | # ignore the "b" and "r" | ||
29 | result = Version("1.0b") == Version("1.0r") | ||
30 | self.assertTrue( result ,msg="Failed to compare version '1.0b' to '1.0r'") | ||
31 | |||
32 | # consider the trailing alphabet as patched level when comparing | ||
33 | result = Version("1.0b","alphabetical") < Version("1.0r","alphabetical") | ||
34 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'") | ||
35 | result = Version("1.0b","alphabetical") > Version("1.0","alphabetical") | ||
36 | self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'") | ||