From: Lee Chee Yang <chee.yang....@intel.com>

The way distutils.version.LooseVersion compare version are tricky, it treat
all these ( "1.0-beta2", "1.0-rc1", "1.0A", "1.0p2" and "1.0pre1") as greater
version than "1.0". This might be right for "1.0A" and "1.0p1" but not for
the rest, also these version could be confusing, the "p" in "1.0p1" can be
"pre" or "patched" version or even other meaning.

replace Looseversion with custom class, it uses regex to capture common
version format like "1.1.1" or tag format using date like "2020-12-12" as
release section, check for following known string/label (beta, rc, pre, dev,
alpha, preview) as pre-release section, any other trailing characters
are difficult to understand and define so dont consider these when
comparing. compare release section and pre-release section saperately.

[YOCTO#14127]

Signed-off-by: Lee Chee Yang <chee.yang....@intel.com>
---
 meta/classes/cve-check.bbclass | 55 ++++++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index d843e7c4ac..b119353781 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -206,7 +206,52 @@ def check_cves(d, patched_cves):
     """
     Connect to the NVD database and find unpatched cves.
     """
-    from distutils.version import LooseVersion
+    import collections, re, itertools
+
+    _Version = collections.namedtuple(
+        "_Version", ["release", "pre_l", "pre_v"]
+    )
+
+    class Version():
+        _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]+)?)?)(.*)?"""
+        _regex = re.compile(r"^\s*" + _version_pattern + r"\s*$", re.VERBOSE | 
re.IGNORECASE)
+        def __init__(self, version):
+            match = self._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(".")),
+                pre_l=match.group("pre_l"),
+                pre_v=match.group("pre_v")
+            )
+
+            self._key = _cmpkey(
+                self._version.release,
+                self._version.pre_l,
+                self._version.pre_v
+            )
+
+        def __ge__(self, other):
+            if not isinstance(other, Version):
+                return NotImplemented
+            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):
+        # remove leading 0
+        _release = tuple(
+            reversed(list(itertools.dropwhile(lambda x: x == 0, 
reversed(release))))
+        )
+        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
 
     pn = d.getVar("PN")
     real_pv = d.getVar("PV")
@@ -263,8 +308,8 @@ def check_cves(d, patched_cves):
                 else:
                     if operator_start:
                         try:
-                            vulnerable_start =  (operator_start == '>=' and 
LooseVersion(pv) >= LooseVersion(version_start))
-                            vulnerable_start |= (operator_start == '>' and 
LooseVersion(pv) > LooseVersion(version_start))
+                            vulnerable_start =  (operator_start == '>=' and 
Version(pv) >= Version(version_start))
+                            vulnerable_start |= (operator_start == '>' and 
Version(pv) > Version(version_start))
                         except:
                             bb.warn("%s: Failed to compare %s %s %s for %s" %
                                     (product, pv, operator_start, 
version_start, cve))
@@ -274,8 +319,8 @@ def check_cves(d, patched_cves):
 
                     if operator_end:
                         try:
-                            vulnerable_end  = (operator_end == '<=' and 
LooseVersion(pv) <= LooseVersion(version_end))
-                            vulnerable_end |= (operator_end == '<' and 
LooseVersion(pv) < LooseVersion(version_end))
+                            vulnerable_end  = (operator_end == '<=' and 
Version(version_end) >= Version(pv))
+                            vulnerable_end |= (operator_end == '<' and 
Version(version_end) > Version(pv) )
                         except:
                             bb.warn("%s: Failed to compare %s %s %s for %s" %
                                     (product, pv, operator_end, version_end, 
cve))
-- 
2.17.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#147042): 
https://lists.openembedded.org/g/openembedded-core/message/147042
Mute This Topic: https://lists.openembedded.org/mt/79995299/21656
Group Owner: openembedded-core+ow...@lists.openembedded.org
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to