summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/classes/cve-check.bbclass43
1 files changed, 30 insertions, 13 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 1b4910f737..50b9247f46 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -47,7 +47,9 @@ CVE_CHECK_MANIFEST_JSON ?= "${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}${IMAGE_NAME_SUFFIX
47CVE_CHECK_COPY_FILES ??= "1" 47CVE_CHECK_COPY_FILES ??= "1"
48CVE_CHECK_CREATE_MANIFEST ??= "1" 48CVE_CHECK_CREATE_MANIFEST ??= "1"
49 49
50# Report Patched or Ignored CVEs
50CVE_CHECK_REPORT_PATCHED ??= "1" 51CVE_CHECK_REPORT_PATCHED ??= "1"
52
51CVE_CHECK_SHOW_WARNINGS ??= "1" 53CVE_CHECK_SHOW_WARNINGS ??= "1"
52 54
53# Provide text output 55# Provide text output
@@ -144,7 +146,7 @@ python do_cve_check () {
144 bb.fatal("Failure in searching patches") 146 bb.fatal("Failure in searching patches")
145 ignored, patched, unpatched, status = check_cves(d, patched_cves) 147 ignored, patched, unpatched, status = check_cves(d, patched_cves)
146 if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" and status): 148 if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" and status):
147 cve_data = get_cve_info(d, patched + unpatched) 149 cve_data = get_cve_info(d, patched + unpatched + ignored)
148 cve_write_data(d, patched, unpatched, ignored, cve_data, status) 150 cve_write_data(d, patched, unpatched, ignored, cve_data, status)
149 else: 151 else:
150 bb.note("No CVE database found, skipping CVE check") 152 bb.note("No CVE database found, skipping CVE check")
@@ -258,6 +260,7 @@ def check_cves(d, patched_cves):
258 suffix = d.getVar("CVE_VERSION_SUFFIX") 260 suffix = d.getVar("CVE_VERSION_SUFFIX")
259 261
260 cves_unpatched = [] 262 cves_unpatched = []
263 cves_ignored = []
261 cves_status = [] 264 cves_status = []
262 cves_in_recipe = False 265 cves_in_recipe = False
263 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) 266 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl)
@@ -291,9 +294,8 @@ def check_cves(d, patched_cves):
291 cve = cverow[0] 294 cve = cverow[0]
292 295
293 if cve in cve_ignore: 296 if cve in cve_ignore:
294 bb.note("%s-%s has been ignored for %s" % (product, pv, cve)) 297 bb.note("%s-%s ignores %s" % (product, pv, cve))
295 # TODO: this should be in the report as 'ignored' 298 cves_ignored.append(cve)
296 patched_cves.add(cve)
297 continue 299 continue
298 elif cve in patched_cves: 300 elif cve in patched_cves:
299 bb.note("%s has been patched" % (cve)) 301 bb.note("%s has been patched" % (cve))
@@ -305,9 +307,13 @@ def check_cves(d, patched_cves):
305 cves_in_recipe = True 307 cves_in_recipe = True
306 308
307 vulnerable = False 309 vulnerable = False
310 ignored = False
311
308 for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): 312 for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)):
309 (_, _, _, version_start, operator_start, version_end, operator_end) = row 313 (_, _, _, version_start, operator_start, version_end, operator_end) = row
310 #bb.debug(2, "Evaluating row " + str(row)) 314 #bb.debug(2, "Evaluating row " + str(row))
315 if cve in cve_ignore:
316 ignored = True
311 317
312 if (operator_start == '=' and pv == version_start) or version_start == '-': 318 if (operator_start == '=' and pv == version_start) or version_start == '-':
313 vulnerable = True 319 vulnerable = True
@@ -340,13 +346,16 @@ def check_cves(d, patched_cves):
340 vulnerable = vulnerable_start or vulnerable_end 346 vulnerable = vulnerable_start or vulnerable_end
341 347
342 if vulnerable: 348 if vulnerable:
343 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve)) 349 if ignored:
344 cves_unpatched.append(cve) 350 bb.note("%s is ignored in %s-%s" % (cve, pn, real_pv))
351 cves_ignored.append(cve)
352 else:
353 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve))
354 cves_unpatched.append(cve)
345 break 355 break
346 356
347 if not vulnerable: 357 if not vulnerable:
348 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve)) 358 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve))
349 # TODO: not patched but not vulnerable
350 patched_cves.add(cve) 359 patched_cves.add(cve)
351 360
352 if not cves_in_product: 361 if not cves_in_product:
@@ -358,7 +367,7 @@ def check_cves(d, patched_cves):
358 if not cves_in_recipe: 367 if not cves_in_recipe:
359 bb.note("No CVE records for products in recipe %s" % (pn)) 368 bb.note("No CVE records for products in recipe %s" % (pn))
360 369
361 return (list(cve_ignore), list(patched_cves), cves_unpatched, cves_status) 370 return (list(cves_ignored), list(patched_cves), cves_unpatched, cves_status)
362 371
363def get_cve_info(d, cves): 372def get_cve_info(d, cves):
364 """ 373 """
@@ -396,6 +405,8 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data):
396 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() 405 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split()
397 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() 406 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split()
398 407
408 report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1"
409
399 if exclude_layers and layer in exclude_layers: 410 if exclude_layers and layer in exclude_layers:
400 return 411 return
401 412
@@ -403,7 +414,7 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data):
403 return 414 return
404 415
405 # Early exit, the text format does not report packages without CVEs 416 # Early exit, the text format does not report packages without CVEs
406 if not patched+unpatched: 417 if not patched+unpatched+ignored:
407 return 418 return
408 419
409 nvd_link = "https://nvd.nist.gov/vuln/detail/" 420 nvd_link = "https://nvd.nist.gov/vuln/detail/"
@@ -413,13 +424,16 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data):
413 424
414 for cve in sorted(cve_data): 425 for cve in sorted(cve_data):
415 is_patched = cve in patched 426 is_patched = cve in patched
416 if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): 427 is_ignored = cve in ignored
428
429 if (is_patched or is_ignored) and not report_all:
417 continue 430 continue
431
418 write_string += "LAYER: %s\n" % layer 432 write_string += "LAYER: %s\n" % layer
419 write_string += "PACKAGE NAME: %s\n" % d.getVar("PN") 433 write_string += "PACKAGE NAME: %s\n" % d.getVar("PN")
420 write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"), d.getVar("PV")) 434 write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"), d.getVar("PV"))
421 write_string += "CVE: %s\n" % cve 435 write_string += "CVE: %s\n" % cve
422 if cve in ignored: 436 if is_ignored:
423 write_string += "CVE STATUS: Ignored\n" 437 write_string += "CVE STATUS: Ignored\n"
424 elif is_patched: 438 elif is_patched:
425 write_string += "CVE STATUS: Patched\n" 439 write_string += "CVE STATUS: Patched\n"
@@ -496,6 +510,8 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status):
496 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() 510 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split()
497 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() 511 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split()
498 512
513 report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1"
514
499 if exclude_layers and layer in exclude_layers: 515 if exclude_layers and layer in exclude_layers:
500 return 516 return
501 517
@@ -522,10 +538,11 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status):
522 538
523 for cve in sorted(cve_data): 539 for cve in sorted(cve_data):
524 is_patched = cve in patched 540 is_patched = cve in patched
541 is_ignored = cve in ignored
525 status = "Unpatched" 542 status = "Unpatched"
526 if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): 543 if (is_patched or is_ignored) and not report_all:
527 continue 544 continue
528 if cve in ignored: 545 if is_ignored:
529 status = "Ignored" 546 status = "Ignored"
530 elif is_patched: 547 elif is_patched:
531 status = "Patched" 548 status = "Patched"