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 ?= "" # CVE_CHECK_WHITELIST ?= "" +# set to "alphabetical" for version using single alphabetical character as increament release +CVE_VERSION_SUFFIX ??= "" + python cve_save_summary_handler () { import shutil import datetime @@ -210,6 +213,7 @@ def check_cves(d, patched_cves): pn = d.getVar("PN") real_pv = d.getVar("PV") + suffix = d.getVar("CVE_VERSION_SUFFIX") cves_unpatched = [] # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) @@ -263,8 +267,8 @@ def check_cves(d, patched_cves): else: if operator_start: try: - vulnerable_start = (operator_start == '>=' and Version(pv) >= Version(version_start)) - vulnerable_start |= (operator_start == '>' and Version(pv) > Version(version_start)) + vulnerable_start = (operator_start == '>=' and Version(pv,suffix) >= Version(version_start,suffix)) + vulnerable_start |= (operator_start == '>' and Version(pv,suffix) > Version(version_start,suffix)) except: bb.warn("%s: Failed to compare %s %s %s for %s" % (product, pv, operator_start, version_start, cve)) @@ -274,8 +278,8 @@ def check_cves(d, patched_cves): if operator_end: try: - vulnerable_end = (operator_end == '<=' and Version(pv) <= Version(version_end) ) - vulnerable_end |= (operator_end == '<' and Version(pv) < Version(version_end) ) + vulnerable_end = (operator_end == '<=' and Version(pv,suffix) <= Version(version_end,suffix) ) + vulnerable_end |= (operator_end == '<' and Version(pv,suffix) < Version(version_end,suffix) ) except: bb.warn("%s: Failed to compare %s %s %s for %s" % (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 @@ import collections import re import itertools +import functools _Version = collections.namedtuple( - "_Version", ["release", "pre_l", "pre_v"] + "_Version", ["release", "patch_l", "pre_l", "pre_v"] ) +@functools.total_ordering class Version(): - _version_pattern = r"""v?(?:(?P[0-9]+(?:[-\.][0-9]+)*)(?P
[-_\.]?(?P(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P[0-9]+)?)?)(.*)?"""
-    _regex = re.compile(r"^\s*" + _version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE)
-    def __init__(self, version):
-        match = self._regex.search(version)
+
+    def __init__(self, version, suffix=None):
+        if str(suffix) == "alphabetical":
+            version_pattern =  r"""r?v?(?:(?P[0-9]+(?:[-\.][0-9]+)*)(?P[-_\.]?(?P[a-z]))?(?P
[-_\.]?(?P(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P[0-9]+)?)?)(.*)?"""
+        else:
+            version_pattern =  r"""r?v?(?:(?P[0-9]+(?:[-\.][0-9]+)*)(?P
[-_\.]?(?P(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P[0-9]+)?)?)(.*)?"""
+        regex = re.compile(r"^\s*" + version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE)
+
+        match = regex.search(version)
         if not match:
             raise Exception("Invalid version: '{0}'".format(version))
 
         self._version = _Version(
             release=tuple(int(i) for i in match.group("release").replace("-",".").split(".")),
+            patch_l=match.group("patch_l") if str(suffix) == "alphabetical" and match.group("patch_l") else "",
             pre_l=match.group("pre_l"),
             pre_v=match.group("pre_v")
         )
 
         self._key = _cmpkey(
             self._version.release,
+            self._version.patch_l,
             self._version.pre_l,
             self._version.pre_v
         )
 
-    def __le__(self, other):
+    def __eq__(self, other):
         if not isinstance(other, Version):
             return NotImplemented
-        return self._key <= other._key
-
-    def __lt__(self, other):
-        if not isinstance(other, Version):
-            return NotImplemented
-        return self._key < other._key
-
-    def __ge__(self, other):
-        if not isinstance(other, Version):
-            return NotImplemented
-        return self._key >= other._key
+        return self._key == other._key
 
     def __gt__(self, other):
         if not isinstance(other, Version):
             return NotImplemented
         return self._key > other._key
 
-def _cmpkey(release, pre_l, pre_v):
+def _cmpkey(release, patch_l, pre_l, pre_v):
     # remove leading 0
     _release = tuple(
         reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
     )
+
+    _patch = patch_l.upper()
+
     if pre_l is None and pre_v is None:
         _pre = float('inf')
     else:
         _pre = float(pre_v) if pre_v else float('-inf')
-    return _release, _pre
+    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):
         self.assertTrue( result, msg="Failed to compare version '1.0_dev' <= '1.0'")
 
         # ignore "p1" and "p2", so these should be equal
-        result = Version("1.0p2") <= Version("1.0p1") and Version("1.0p2") >= Version("1.0p1")
+        result = Version("1.0p2") == Version("1.0p1")
         self.assertTrue( result ,msg="Failed to compare version '1.0p2' to '1.0p1'")
+        # ignore the "b" and "r"
+        result = Version("1.0b") == Version("1.0r")
+        self.assertTrue( result ,msg="Failed to compare version '1.0b' to '1.0r'")
+
+        # consider the trailing alphabet as patched level when comparing
+        result = Version("1.0b","alphabetical") < Version("1.0r","alphabetical")
+        self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' < '1.0r'")
+        result = Version("1.0b","alphabetical") > Version("1.0","alphabetical")
+        self.assertTrue( result ,msg="Failed to compare version with suffix '1.0b' > '1.0'")