summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/classes/cve-check.bbclass12
-rw-r--r--meta/lib/oe/cve_check.py40
-rw-r--r--meta/lib/oeqa/selftest/cases/cve_check.py11
3 files changed, 39 insertions, 24 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 93af667544..dbff852e18 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -50,6 +50,9 @@ CVE_CHECK_PN_WHITELIST ?= ""
50# 50#
51CVE_CHECK_WHITELIST ?= "" 51CVE_CHECK_WHITELIST ?= ""
52 52
53# set to "alphabetical" for version using single alphabetical character as increament release
54CVE_VERSION_SUFFIX ??= ""
55
53python cve_save_summary_handler () { 56python cve_save_summary_handler () {
54 import shutil 57 import shutil
55 import datetime 58 import datetime
@@ -207,6 +210,7 @@ def check_cves(d, patched_cves):
207 210
208 pn = d.getVar("PN") 211 pn = d.getVar("PN")
209 real_pv = d.getVar("PV") 212 real_pv = d.getVar("PV")
213 suffix = d.getVar("CVE_VERSION_SUFFIX")
210 214
211 cves_unpatched = [] 215 cves_unpatched = []
212 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) 216 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl)
@@ -260,8 +264,8 @@ def check_cves(d, patched_cves):
260 else: 264 else:
261 if operator_start: 265 if operator_start:
262 try: 266 try:
263 vulnerable_start = (operator_start == '>=' and Version(pv) >= Version(version_start)) 267 vulnerable_start = (operator_start == '>=' and Version(pv,suffix) >= Version(version_start,suffix))
264 vulnerable_start |= (operator_start == '>' and Version(pv) > Version(version_start)) 268 vulnerable_start |= (operator_start == '>' and Version(pv,suffix) > Version(version_start,suffix))
265 except: 269 except:
266 bb.warn("%s: Failed to compare %s %s %s for %s" % 270 bb.warn("%s: Failed to compare %s %s %s for %s" %
267 (product, pv, operator_start, version_start, cve)) 271 (product, pv, operator_start, version_start, cve))
@@ -271,8 +275,8 @@ def check_cves(d, patched_cves):
271 275
272 if operator_end: 276 if operator_end:
273 try: 277 try:
274 vulnerable_end = (operator_end == '<=' and Version(pv) <= Version(version_end) ) 278 vulnerable_end = (operator_end == '<=' and Version(pv,suffix) <= Version(version_end,suffix) )
275 vulnerable_end |= (operator_end == '<' and Version(pv) < Version(version_end) ) 279 vulnerable_end |= (operator_end == '<' and Version(pv,suffix) < Version(version_end,suffix) )
276 except: 280 except:
277 bb.warn("%s: Failed to compare %s %s %s for %s" % 281 bb.warn("%s: Failed to compare %s %s %s for %s" %
278 (product, pv, operator_end, version_end, cve)) 282 (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 @@
1import collections 1import collections
2import re 2import re
3import itertools 3import itertools
4import 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
9class Version(): 11class 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
49def _cmpkey(release, pre_l, pre_v): 48def _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'")