summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarta Rybczynska <rybczynska@gmail.com>2025-02-13 06:57:52 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-02-18 11:56:04 +0000
commit0486af6e3cefeeb705ec7c7a0938623fc25d9fee (patch)
treefd8e6e698f5e9f7f904e5dbcfa6df7609b0783e6
parent7a3904c6a730272841941a20531aa1616cc608c5 (diff)
downloadpoky-0486af6e3cefeeb705ec7c7a0938623fc25d9fee.tar.gz
cve-update-db-native: add the fkie source
Add support for FKIE-CAD reconstruction of NVD feed from https://github.com/fkie-cad/nvd-json-data-feeds We download this feed directly from github releases. (From OE-Core rev: f6253ac8189db09fbe87141aca1733cb37a4d78f) Signed-off-by: Marta Rybczynska <marta.rybczynska@ygreky.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-core/meta/cve-update-db-native.bb126
1 files changed, 113 insertions, 13 deletions
diff --git a/meta/recipes-core/meta/cve-update-db-native.bb b/meta/recipes-core/meta/cve-update-db-native.bb
index 3a9d43943c..792252f510 100644
--- a/meta/recipes-core/meta/cve-update-db-native.bb
+++ b/meta/recipes-core/meta/cve-update-db-native.bb
@@ -12,6 +12,8 @@ deltask do_install
12deltask do_populate_sysroot 12deltask do_populate_sysroot
13 13
14NVDCVE_URL ?= "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-" 14NVDCVE_URL ?= "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-"
15FKIE_URL ?= "https://github.com/fkie-cad/nvd-json-data-feeds/releases/latest/download/CVE-"
16
15# CVE database update interval, in seconds. By default: once a day (24*60*60). 17# CVE database update interval, in seconds. By default: once a day (24*60*60).
16# Use 0 to force the update 18# Use 0 to force the update
17# Use a negative value to skip the update 19# Use a negative value to skip the update
@@ -109,6 +111,30 @@ def cleanup_db_download(db_file, db_tmp_file):
109 if os.path.exists(db_tmp_file): 111 if os.path.exists(db_tmp_file):
110 os.remove(db_tmp_file) 112 os.remove(db_tmp_file)
111 113
114def db_file_names(d, year, is_nvd):
115 if is_nvd:
116 year_url = d.getVar('NVDCVE_URL') + str(year)
117 meta_url = year_url + ".meta"
118 json_url = year_url + ".json.gz"
119 return json_url, meta_url
120 year_url = d.getVar('FKIE_URL') + str(year)
121 meta_url = year_url + ".meta"
122 json_url = year_url + ".json.xz"
123 return json_url, meta_url
124
125def host_db_name(d, is_nvd):
126 if is_nvd:
127 return "nvd.nist.gov"
128 return "github.com"
129
130def db_decompress(d, data, is_nvd):
131 import gzip, lzma
132
133 if is_nvd:
134 return gzip.decompress(data).decode('utf-8')
135 # otherwise
136 return lzma.decompress(data)
137
112def update_db_file(db_tmp_file, d): 138def update_db_file(db_tmp_file, d):
113 """ 139 """
114 Update the given database file 140 Update the given database file
@@ -119,6 +145,7 @@ def update_db_file(db_tmp_file, d):
119 145
120 YEAR_START = 2002 146 YEAR_START = 2002
121 cve_socket_timeout = int(d.getVar("CVE_SOCKET_TIMEOUT")) 147 cve_socket_timeout = int(d.getVar("CVE_SOCKET_TIMEOUT"))
148 is_nvd = d.getVar("NVD_DB_VERSION") == "NVD1"
122 149
123 # Connect to database 150 # Connect to database
124 conn = sqlite3.connect(db_tmp_file) 151 conn = sqlite3.connect(db_tmp_file)
@@ -129,9 +156,7 @@ def update_db_file(db_tmp_file, d):
129 for i, year in enumerate(range(YEAR_START, date.today().year + 1)): 156 for i, year in enumerate(range(YEAR_START, date.today().year + 1)):
130 bb.debug(2, "Updating %d" % year) 157 bb.debug(2, "Updating %d" % year)
131 ph.update((float(i + 1) / total_years) * 100) 158 ph.update((float(i + 1) / total_years) * 100)
132 year_url = (d.getVar('NVDCVE_URL')) + str(year) 159 json_url, meta_url = db_file_names(d, year, is_nvd)
133 meta_url = year_url + ".meta"
134 json_url = year_url + ".json.gz"
135 160
136 # Retrieve meta last modified date 161 # Retrieve meta last modified date
137 try: 162 try:
@@ -140,7 +165,7 @@ def update_db_file(db_tmp_file, d):
140 cve_f.write('Warning: CVE db update error, Unable to fetch CVE data.\n\n') 165 cve_f.write('Warning: CVE db update error, Unable to fetch CVE data.\n\n')
141 bb.warn("Failed to fetch CVE data (%s)" % e) 166 bb.warn("Failed to fetch CVE data (%s)" % e)
142 import socket 167 import socket
143 result = socket.getaddrinfo("nvd.nist.gov", 443, proto=socket.IPPROTO_TCP) 168 result = socket.getaddrinfo(host_db_name(d, is_nvd), 443, proto=socket.IPPROTO_TCP)
144 bb.warn("Host IPs are %s" % (", ".join(t[4][0] for t in result))) 169 bb.warn("Host IPs are %s" % (", ".join(t[4][0] for t in result)))
145 return False 170 return False
146 171
@@ -168,7 +193,7 @@ def update_db_file(db_tmp_file, d):
168 try: 193 try:
169 response = urllib.request.urlopen(json_url, timeout=cve_socket_timeout) 194 response = urllib.request.urlopen(json_url, timeout=cve_socket_timeout)
170 if response: 195 if response:
171 update_db(conn, gzip.decompress(response.read()).decode('utf-8')) 196 update_db(d, conn, db_decompress(d, response.read(), is_nvd))
172 conn.execute("insert or replace into META values (?, ?)", [year, last_modified]).close() 197 conn.execute("insert or replace into META values (?, ?)", [year, last_modified]).close()
173 except urllib.error.URLError as e: 198 except urllib.error.URLError as e:
174 cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n') 199 cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n')
@@ -200,16 +225,22 @@ def initialize_db(conn):
200 225
201 c.close() 226 c.close()
202 227
203def parse_node_and_insert(conn, node, cveId): 228def parse_node_and_insert(conn, node, cveId, is_nvd):
204 # Parse children node if needed 229 # Parse children node if needed
205 for child in node.get('children', ()): 230 for child in node.get('children', ()):
206 parse_node_and_insert(conn, child, cveId) 231 parse_node_and_insert(conn, child, cveId, is_nvd)
232
233 def cpe_generator(is_nvd):
234 match_string = "cpeMatch"
235 cpe_string = 'criteria'
236 if is_nvd:
237 match_string = "cpe_match"
238 cpe_string = 'cpe23Uri'
207 239
208 def cpe_generator(): 240 for cpe in node.get(match_string, ()):
209 for cpe in node.get('cpe_match', ()):
210 if not cpe['vulnerable']: 241 if not cpe['vulnerable']:
211 return 242 return
212 cpe23 = cpe.get('cpe23Uri') 243 cpe23 = cpe.get(cpe_string)
213 if not cpe23: 244 if not cpe23:
214 return 245 return
215 cpe23 = cpe23.split(':') 246 cpe23 = cpe23.split(':')
@@ -260,9 +291,9 @@ def parse_node_and_insert(conn, node, cveId):
260 # Save processing by representing as -. 291 # Save processing by representing as -.
261 yield [cveId, vendor, product, '-', '', '', ''] 292 yield [cveId, vendor, product, '-', '', '', '']
262 293
263 conn.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator()).close() 294 conn.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator(is_nvd)).close()
264 295
265def update_db(conn, jsondata): 296def update_db_nvdjson(conn, jsondata):
266 import json 297 import json
267 root = json.loads(jsondata) 298 root = json.loads(jsondata)
268 299
@@ -297,8 +328,77 @@ def update_db(conn, jsondata):
297 328
298 configurations = elt['configurations']['nodes'] 329 configurations = elt['configurations']['nodes']
299 for config in configurations: 330 for config in configurations:
300 parse_node_and_insert(conn, config, cveId) 331 parse_node_and_insert(conn, config, cveId, True)
332
333def update_db_fkie(conn, jsondata):
334 import json
335 root = json.loads(jsondata)
336
337 for elt in root['cve_items']:
338 if not 'vulnStatus' in elt or elt['vulnStatus'] == 'Rejected':
339 continue
340
341 if not 'configurations' in elt:
342 continue
343
344 accessVector = None
345 vectorString = None
346 cvssv2 = 0.0
347 cvssv3 = 0.0
348 cvssv4 = 0.0
349 cveId = elt['id']
350 cveDesc = elt['descriptions'][0]['value']
351 date = elt['lastModified']
352 try:
353 for m in elt['metrics']['cvssMetricV2']:
354 if m['type'] == 'Primary':
355 accessVector = m['cvssData']['accessVector']
356 vectorString = m['cvssData']['vectorString']
357 cvssv2 = m['cvssData']['baseScore']
358 except KeyError:
359 cvssv2 = 0.0
360 try:
361 for m in elt['metrics']['cvssMetricV30']:
362 if m['type'] == 'Primary':
363 accessVector = m['cvssData']['accessVector']
364 vectorString = m['cvssData']['vectorString']
365 cvssv3 = m['cvssData']['baseScore']
366 except KeyError:
367 accessVector = accessVector or "UNKNOWN"
368 cvssv3 = 0.0
369 try:
370 for m in elt['metrics']['cvssMetricV31']:
371 if m['type'] == 'Primary':
372 accessVector = m['cvssData']['accessVector']
373 vectorString = m['cvssData']['vectorString']
374 cvssv3 = m['cvssData']['baseScore']
375 except KeyError:
376 accessVector = accessVector or "UNKNOWN"
377 cvssv3 = 0.0
378 try:
379 for m in elt['metrics']['cvssMetricV40']:
380 if m['type'] == 'Primary':
381 accessVector = m['cvssData']['accessVector']
382 vectorString = m['cvssData']['vectorString']
383 cvssv4 = m['cvssData']['baseScore']
384 except KeyError:
385 accessVector = accessVector or "UNKNOWN"
386 cvssv4 = 0.0
301 387
388 conn.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?, ?, ?)",
389 [cveId, cveDesc, cvssv2, cvssv3, cvssv4, date, accessVector, vectorString]).close()
390
391 for config in elt['configurations']:
392 # This is suboptimal as it doesn't handle AND/OR and negate, but is better than nothing
393 for node in config["nodes"]:
394 parse_node_and_insert(conn, node, cveId, False)
395
396
397def update_db(d, conn, jsondata):
398 if (d.getVar("NVD_DB_VERSION") == "FKIE"):
399 return update_db_fkie(conn, jsondata)
400 else:
401 return update_db_nvdjson(conn, jsondata)
302 402
303do_fetch[nostamp] = "1" 403do_fetch[nostamp] = "1"
304 404