summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoss Burton <ross.burton@arm.com>2022-08-26 18:35:47 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2022-09-12 08:41:52 +0100
commit0bee2e95b7133be6c2bf8572d7bef43fee58ba66 (patch)
treed3b31a3993d59836e2357cab798cb8d1081f244e
parent7ba4ed6f5fcbc0878723e41281e927c1caa46a0b (diff)
downloadpoky-0bee2e95b7133be6c2bf8572d7bef43fee58ba66.tar.gz
cve-check: close cursors as soon as possible
We can have multiple processes reading the database at the same time, and cursors only release their locks when they're garbage collected. This might be the cause of random sqlite errors on the autobuilder, so explicitly close the cursors when we're done with them. (From OE-Core rev: 48742ddf4d0acd419c8ffb8f22124ed525efc2d9) Signed-off-by: Ross Burton <ross.burton@arm.com> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com> (cherry picked from commit 5d2e90e4a58217a943ec21140bc2ecdd4357a98a) Signed-off-by: Steve Sakoman <steve@sakoman.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/classes/cve-check.bbclass13
-rw-r--r--meta/recipes-core/meta/cve-update-db-native.bb51
2 files changed, 37 insertions, 27 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index c0d4e2a972..4fc4e545e4 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -290,7 +290,8 @@ def check_cves(d, patched_cves):
290 vendor = "%" 290 vendor = "%"
291 291
292 # Find all relevant CVE IDs. 292 # Find all relevant CVE IDs.
293 for cverow in conn.execute("SELECT DISTINCT ID FROM PRODUCTS WHERE PRODUCT IS ? AND VENDOR LIKE ?", (product, vendor)): 293 cve_cursor = conn.execute("SELECT DISTINCT ID FROM PRODUCTS WHERE PRODUCT IS ? AND VENDOR LIKE ?", (product, vendor))
294 for cverow in cve_cursor:
294 cve = cverow[0] 295 cve = cverow[0]
295 296
296 if cve in cve_whitelist: 297 if cve in cve_whitelist:
@@ -309,7 +310,8 @@ def check_cves(d, patched_cves):
309 vulnerable = False 310 vulnerable = False
310 ignored = False 311 ignored = False
311 312
312 for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): 313 product_cursor = conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor))
314 for row in product_cursor:
313 (_, _, _, version_start, operator_start, version_end, operator_end) = row 315 (_, _, _, version_start, operator_start, version_end, operator_end) = row
314 #bb.debug(2, "Evaluating row " + str(row)) 316 #bb.debug(2, "Evaluating row " + str(row))
315 if cve in cve_whitelist: 317 if cve in cve_whitelist:
@@ -353,10 +355,12 @@ def check_cves(d, patched_cves):
353 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve)) 355 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve))
354 cves_unpatched.append(cve) 356 cves_unpatched.append(cve)
355 break 357 break
358 product_cursor.close()
356 359
357 if not vulnerable: 360 if not vulnerable:
358 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve)) 361 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve))
359 patched_cves.add(cve) 362 patched_cves.add(cve)
363 cve_cursor.close()
360 364
361 if not cves_in_product: 365 if not cves_in_product:
362 bb.note("No CVE records found for product %s, pn %s" % (product, pn)) 366 bb.note("No CVE records found for product %s, pn %s" % (product, pn))
@@ -378,14 +382,15 @@ def get_cve_info(d, cves):
378 conn = sqlite3.connect(db_file, uri=True) 382 conn = sqlite3.connect(db_file, uri=True)
379 383
380 for cve in cves: 384 for cve in cves:
381 for row in conn.execute("SELECT * FROM NVD WHERE ID IS ?", (cve,)): 385 cursor = conn.execute("SELECT * FROM NVD WHERE ID IS ?", (cve,))
386 for row in cursor:
382 cve_data[row[0]] = {} 387 cve_data[row[0]] = {}
383 cve_data[row[0]]["summary"] = row[1] 388 cve_data[row[0]]["summary"] = row[1]
384 cve_data[row[0]]["scorev2"] = row[2] 389 cve_data[row[0]]["scorev2"] = row[2]
385 cve_data[row[0]]["scorev3"] = row[3] 390 cve_data[row[0]]["scorev3"] = row[3]
386 cve_data[row[0]]["modified"] = row[4] 391 cve_data[row[0]]["modified"] = row[4]
387 cve_data[row[0]]["vector"] = row[5] 392 cve_data[row[0]]["vector"] = row[5]
388 393 cursor.close()
389 conn.close() 394 conn.close()
390 return cve_data 395 return cve_data
391 396
diff --git a/meta/recipes-core/meta/cve-update-db-native.bb b/meta/recipes-core/meta/cve-update-db-native.bb
index a49f446a53..85874ead01 100644
--- a/meta/recipes-core/meta/cve-update-db-native.bb
+++ b/meta/recipes-core/meta/cve-update-db-native.bb
@@ -65,9 +65,7 @@ python do_fetch() {
65 65
66 # Connect to database 66 # Connect to database
67 conn = sqlite3.connect(db_file) 67 conn = sqlite3.connect(db_file)
68 c = conn.cursor() 68 initialize_db(conn)
69
70 initialize_db(c)
71 69
72 with bb.progress.ProgressHandler(d) as ph, open(os.path.join(d.getVar("TMPDIR"), 'cve_check'), 'a') as cve_f: 70 with bb.progress.ProgressHandler(d) as ph, open(os.path.join(d.getVar("TMPDIR"), 'cve_check'), 'a') as cve_f:
73 total_years = date.today().year + 1 - YEAR_START 71 total_years = date.today().year + 1 - YEAR_START
@@ -96,18 +94,20 @@ python do_fetch() {
96 return 94 return
97 95
98 # Compare with current db last modified date 96 # Compare with current db last modified date
99 c.execute("select DATE from META where YEAR = ?", (year,)) 97 cursor = conn.execute("select DATE from META where YEAR = ?", (year,))
100 meta = c.fetchone() 98 meta = cursor.fetchone()
99 cursor.close()
100
101 if not meta or meta[0] != last_modified: 101 if not meta or meta[0] != last_modified:
102 # Clear products table entries corresponding to current year 102 # Clear products table entries corresponding to current year
103 c.execute("delete from PRODUCTS where ID like ?", ('CVE-%d%%' % year,)) 103 conn.execute("delete from PRODUCTS where ID like ?", ('CVE-%d%%' % year,)).close()
104 104
105 # Update db with current year json file 105 # Update db with current year json file
106 try: 106 try:
107 response = urllib.request.urlopen(json_url) 107 response = urllib.request.urlopen(json_url)
108 if response: 108 if response:
109 update_db(c, gzip.decompress(response.read()).decode('utf-8')) 109 update_db(conn, gzip.decompress(response.read()).decode('utf-8'))
110 c.execute("insert or replace into META values (?, ?)", [year, last_modified]) 110 conn.execute("insert or replace into META values (?, ?)", [year, last_modified]).close()
111 except urllib.error.URLError as e: 111 except urllib.error.URLError as e:
112 cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n') 112 cve_f.write('Warning: CVE db update error, CVE data is outdated.\n\n')
113 bb.warn("Cannot parse CVE data (%s), update failed" % e.reason) 113 bb.warn("Cannot parse CVE data (%s), update failed" % e.reason)
@@ -125,21 +125,26 @@ do_fetch[lockfiles] += "${CVE_CHECK_DB_FILE_LOCK}"
125do_fetch[file-checksums] = "" 125do_fetch[file-checksums] = ""
126do_fetch[vardeps] = "" 126do_fetch[vardeps] = ""
127 127
128def initialize_db(c): 128def initialize_db(conn):
129 c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE TEXT)") 129 with conn:
130 c = conn.cursor()
131
132 c.execute("CREATE TABLE IF NOT EXISTS META (YEAR INTEGER UNIQUE, DATE TEXT)")
133
134 c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \
135 SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)")
130 136
131 c.execute("CREATE TABLE IF NOT EXISTS NVD (ID TEXT UNIQUE, SUMMARY TEXT, \ 137 c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (ID TEXT, \
132 SCOREV2 TEXT, SCOREV3 TEXT, MODIFIED INTEGER, VECTOR TEXT)") 138 VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START TEXT, \
139 VERSION_END TEXT, OPERATOR_END TEXT)")
140 c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_ID_IDX on PRODUCTS(ID);")
133 141
134 c.execute("CREATE TABLE IF NOT EXISTS PRODUCTS (ID TEXT, \ 142 c.close()
135 VENDOR TEXT, PRODUCT TEXT, VERSION_START TEXT, OPERATOR_START TEXT, \
136 VERSION_END TEXT, OPERATOR_END TEXT)")
137 c.execute("CREATE INDEX IF NOT EXISTS PRODUCT_ID_IDX on PRODUCTS(ID);")
138 143
139def parse_node_and_insert(c, node, cveId): 144def parse_node_and_insert(conn, node, cveId):
140 # Parse children node if needed 145 # Parse children node if needed
141 for child in node.get('children', ()): 146 for child in node.get('children', ()):
142 parse_node_and_insert(c, child, cveId) 147 parse_node_and_insert(conn, child, cveId)
143 148
144 def cpe_generator(): 149 def cpe_generator():
145 for cpe in node.get('cpe_match', ()): 150 for cpe in node.get('cpe_match', ()):
@@ -196,9 +201,9 @@ def parse_node_and_insert(c, node, cveId):
196 # Save processing by representing as -. 201 # Save processing by representing as -.
197 yield [cveId, vendor, product, '-', '', '', ''] 202 yield [cveId, vendor, product, '-', '', '', '']
198 203
199 c.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator()) 204 conn.executemany("insert into PRODUCTS values (?, ?, ?, ?, ?, ?, ?)", cpe_generator()).close()
200 205
201def update_db(c, jsondata): 206def update_db(conn, jsondata):
202 import json 207 import json
203 root = json.loads(jsondata) 208 root = json.loads(jsondata)
204 209
@@ -222,12 +227,12 @@ def update_db(c, jsondata):
222 accessVector = accessVector or "UNKNOWN" 227 accessVector = accessVector or "UNKNOWN"
223 cvssv3 = 0.0 228 cvssv3 = 0.0
224 229
225 c.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)", 230 conn.execute("insert or replace into NVD values (?, ?, ?, ?, ?, ?)",
226 [cveId, cveDesc, cvssv2, cvssv3, date, accessVector]) 231 [cveId, cveDesc, cvssv2, cvssv3, date, accessVector]).close()
227 232
228 configurations = elt['configurations']['nodes'] 233 configurations = elt['configurations']['nodes']
229 for config in configurations: 234 for config in configurations:
230 parse_node_and_insert(c, config, cveId) 235 parse_node_and_insert(conn, config, cveId)
231 236
232 237
233do_fetch[nostamp] = "1" 238do_fetch[nostamp] = "1"