|
@@ -47,6 +47,24 @@ ops = {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+# Check if two CPE IDs match each other
|
|
|
|
+def cpe_matches(cpe1, cpe2):
|
|
|
|
+ cpe1_elems = cpe1.split(":")
|
|
|
|
+ cpe2_elems = cpe2.split(":")
|
|
|
|
+
|
|
|
|
+ remains = filter(lambda x: x[0] not in ["*", "-"] and x[1] not in ["*", "-"] and x[0] != x[1],
|
|
|
|
+ zip(cpe1_elems, cpe2_elems))
|
|
|
|
+ return len(list(remains)) == 0
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def cpe_product(cpe):
|
|
|
|
+ return cpe.split(':')[4]
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def cpe_version(cpe):
|
|
|
|
+ return cpe.split(':')[5]
|
|
|
|
+
|
|
|
|
+
|
|
class CVE:
|
|
class CVE:
|
|
"""An accessor class for CVE Items in NVD files"""
|
|
"""An accessor class for CVE Items in NVD files"""
|
|
CVE_AFFECTS = 1
|
|
CVE_AFFECTS = 1
|
|
@@ -134,7 +152,11 @@ class CVE:
|
|
for cpe in node.get('cpe_match', ()):
|
|
for cpe in node.get('cpe_match', ()):
|
|
if not cpe['vulnerable']:
|
|
if not cpe['vulnerable']:
|
|
return
|
|
return
|
|
- vendor, product, version = cpe['cpe23Uri'].split(':')[3:6]
|
|
|
|
|
|
+ product = cpe_product(cpe['cpe23Uri'])
|
|
|
|
+ version = cpe_version(cpe['cpe23Uri'])
|
|
|
|
+ # ignore when product is '-', which means N/A
|
|
|
|
+ if product == '-':
|
|
|
|
+ return
|
|
op_start = ''
|
|
op_start = ''
|
|
op_end = ''
|
|
op_end = ''
|
|
v_start = ''
|
|
v_start = ''
|
|
@@ -163,8 +185,7 @@ class CVE:
|
|
v_end = cpe['versionEndExcluding']
|
|
v_end = cpe['versionEndExcluding']
|
|
|
|
|
|
yield {
|
|
yield {
|
|
- 'vendor': vendor,
|
|
|
|
- 'product': product,
|
|
|
|
|
|
+ 'id': cpe['cpe23Uri'],
|
|
'v_start': v_start,
|
|
'v_start': v_start,
|
|
'op_start': op_start,
|
|
'op_start': op_start,
|
|
'v_end': v_end,
|
|
'v_end': v_end,
|
|
@@ -182,11 +203,11 @@ class CVE:
|
|
return self.nvd_cve['cve']['CVE_data_meta']['ID']
|
|
return self.nvd_cve['cve']['CVE_data_meta']['ID']
|
|
|
|
|
|
@property
|
|
@property
|
|
- def pkg_names(self):
|
|
|
|
- """The set of package names referred by this CVE definition"""
|
|
|
|
- return set(p['product'] for p in self.each_cpe())
|
|
|
|
|
|
+ def affected_products(self):
|
|
|
|
+ """The set of CPE products referred by this CVE definition"""
|
|
|
|
+ return set(cpe_product(p['id']) for p in self.each_cpe())
|
|
|
|
|
|
- def affects(self, name, version, cve_ignore_list):
|
|
|
|
|
|
+ def affects(self, name, version, cve_ignore_list, cpeid=None):
|
|
"""
|
|
"""
|
|
True if the Buildroot Package object passed as argument is affected
|
|
True if the Buildroot Package object passed as argument is affected
|
|
by this CVE.
|
|
by this CVE.
|
|
@@ -199,8 +220,12 @@ class CVE:
|
|
print("Cannot parse package '%s' version '%s'" % (name, version))
|
|
print("Cannot parse package '%s' version '%s'" % (name, version))
|
|
pkg_version = None
|
|
pkg_version = None
|
|
|
|
|
|
|
|
+ # if we don't have a cpeid, build one based on name and version
|
|
|
|
+ if not cpeid:
|
|
|
|
+ cpeid = "cpe:2.3:*:*:%s:%s:*:*:*:*:*:*:*" % (name, version)
|
|
|
|
+
|
|
for cpe in self.each_cpe():
|
|
for cpe in self.each_cpe():
|
|
- if cpe['product'] != name:
|
|
|
|
|
|
+ if not cpe_matches(cpe['id'], cpeid):
|
|
continue
|
|
continue
|
|
if not cpe['v_start'] and not cpe['v_end']:
|
|
if not cpe['v_start'] and not cpe['v_end']:
|
|
return self.CVE_AFFECTS
|
|
return self.CVE_AFFECTS
|