summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Chee Yang <chee.yang.lee@intel.com>2021-01-29 11:51:15 +0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-01-30 10:41:04 +0000
commit86b42289bda5bc2a4eff221ab476f170dd3d3794 (patch)
treee936bb438cb97ea1a07db5517bc29524e2af501f
parentef208aaf0f05c478a3dbade3d2bfd3744f91d87e (diff)
downloadpoky-86b42289bda5bc2a4eff221ab476f170dd3d3794.tar.gz
cve_check: add CVE_VERSION_SUFFIX to indicate suffix in versioning
add CVE_VERSION_SUFFIX to indicate the version suffix type, currently works in two value, "alphabetical" if the version string uses single alphabetical character suffix as incremental release, blank to not consider the unidentified suffixes. This can be expand when more suffix pattern identified. refactor cve_check.Version class to use functools and add parameter to handle suffix condition. Also update testcases to cover new changes. (From OE-Core rev: 5dfd5ad5144708b474ef31eaa89a846c57be8ac0) Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-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 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#
54CVE_CHECK_WHITELIST ?= "" 54CVE_CHECK_WHITELIST ?= ""
55 55
56# set to "alphabetical" for version using single alphabetical character as increament release
57CVE_VERSION_SUFFIX ??= ""
58
56python cve_save_summary_handler () { 59python 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 @@
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'")