summaryrefslogtreecommitdiffstats
path: root/meta/classes/cve-check.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/cve-check.bbclass')
-rw-r--r--meta/classes/cve-check.bbclass41
1 files changed, 29 insertions, 12 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index 894cebaaa4..d0f6970db8 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/Whitelisted 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
@@ -142,7 +144,7 @@ python do_cve_check () {
142 bb.fatal("Failure in searching patches") 144 bb.fatal("Failure in searching patches")
143 whitelisted, patched, unpatched, status = check_cves(d, patched_cves) 145 whitelisted, patched, unpatched, status = check_cves(d, patched_cves)
144 if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" and status): 146 if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" and status):
145 cve_data = get_cve_info(d, patched + unpatched) 147 cve_data = get_cve_info(d, patched + unpatched + whitelisted)
146 cve_write_data(d, patched, unpatched, whitelisted, cve_data, status) 148 cve_write_data(d, patched, unpatched, whitelisted, cve_data, status)
147 else: 149 else:
148 bb.note("No CVE database found, skipping CVE check") 150 bb.note("No CVE database found, skipping CVE check")
@@ -315,6 +317,7 @@ def check_cves(d, patched_cves):
315 suffix = d.getVar("CVE_VERSION_SUFFIX") 317 suffix = d.getVar("CVE_VERSION_SUFFIX")
316 318
317 cves_unpatched = [] 319 cves_unpatched = []
320 cves_ignored = []
318 cves_status = [] 321 cves_status = []
319 cves_in_recipe = False 322 cves_in_recipe = False
320 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) 323 # CVE_PRODUCT can contain more than one product (eg. curl/libcurl)
@@ -349,8 +352,7 @@ def check_cves(d, patched_cves):
349 352
350 if cve in cve_whitelist: 353 if cve in cve_whitelist:
351 bb.note("%s-%s has been whitelisted for %s" % (product, pv, cve)) 354 bb.note("%s-%s has been whitelisted for %s" % (product, pv, cve))
352 # TODO: this should be in the report as 'whitelisted' 355 cves_ignored.append(cve)
353 patched_cves.add(cve)
354 continue 356 continue
355 elif cve in patched_cves: 357 elif cve in patched_cves:
356 bb.note("%s has been patched" % (cve)) 358 bb.note("%s has been patched" % (cve))
@@ -362,9 +364,13 @@ def check_cves(d, patched_cves):
362 cves_in_recipe = True 364 cves_in_recipe = True
363 365
364 vulnerable = False 366 vulnerable = False
367 ignored = False
368
365 for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): 369 for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)):
366 (_, _, _, version_start, operator_start, version_end, operator_end) = row 370 (_, _, _, version_start, operator_start, version_end, operator_end) = row
367 #bb.debug(2, "Evaluating row " + str(row)) 371 #bb.debug(2, "Evaluating row " + str(row))
372 if cve in cve_whitelist:
373 ignored = True
368 374
369 if (operator_start == '=' and pv == version_start) or version_start == '-': 375 if (operator_start == '=' and pv == version_start) or version_start == '-':
370 vulnerable = True 376 vulnerable = True
@@ -397,13 +403,16 @@ def check_cves(d, patched_cves):
397 vulnerable = vulnerable_start or vulnerable_end 403 vulnerable = vulnerable_start or vulnerable_end
398 404
399 if vulnerable: 405 if vulnerable:
400 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve)) 406 if ignored:
401 cves_unpatched.append(cve) 407 bb.note("%s is ignored in %s-%s" % (cve, pn, real_pv))
408 cves_ignored.append(cve)
409 else:
410 bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve))
411 cves_unpatched.append(cve)
402 break 412 break
403 413
404 if not vulnerable: 414 if not vulnerable:
405 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve)) 415 bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve))
406 # TODO: not patched but not vulnerable
407 patched_cves.add(cve) 416 patched_cves.add(cve)
408 417
409 if not cves_in_product: 418 if not cves_in_product:
@@ -412,7 +421,7 @@ def check_cves(d, patched_cves):
412 421
413 conn.close() 422 conn.close()
414 423
415 return (list(cve_whitelist), list(patched_cves), cves_unpatched, cves_status) 424 return (list(cves_ignored), list(patched_cves), cves_unpatched, cves_status)
416 425
417def get_cve_info(d, cves): 426def get_cve_info(d, cves):
418 """ 427 """
@@ -450,6 +459,8 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data):
450 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() 459 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split()
451 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() 460 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split()
452 461
462 report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1"
463
453 if exclude_layers and layer in exclude_layers: 464 if exclude_layers and layer in exclude_layers:
454 return 465 return
455 466
@@ -457,7 +468,7 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data):
457 return 468 return
458 469
459 # Early exit, the text format does not report packages without CVEs 470 # Early exit, the text format does not report packages without CVEs
460 if not patched+unpatched: 471 if not patched+unpatched+whitelisted:
461 return 472 return
462 473
463 nvd_link = "https://nvd.nist.gov/vuln/detail/" 474 nvd_link = "https://nvd.nist.gov/vuln/detail/"
@@ -467,13 +478,16 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data):
467 478
468 for cve in sorted(cve_data): 479 for cve in sorted(cve_data):
469 is_patched = cve in patched 480 is_patched = cve in patched
470 if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): 481 is_ignored = cve in whitelisted
482
483 if (is_patched or is_ignored) and not report_all:
471 continue 484 continue
485
472 write_string += "LAYER: %s\n" % layer 486 write_string += "LAYER: %s\n" % layer
473 write_string += "PACKAGE NAME: %s\n" % d.getVar("PN") 487 write_string += "PACKAGE NAME: %s\n" % d.getVar("PN")
474 write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"), d.getVar("PV")) 488 write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"), d.getVar("PV"))
475 write_string += "CVE: %s\n" % cve 489 write_string += "CVE: %s\n" % cve
476 if cve in whitelisted: 490 if is_ignored:
477 write_string += "CVE STATUS: Whitelisted\n" 491 write_string += "CVE STATUS: Whitelisted\n"
478 elif is_patched: 492 elif is_patched:
479 write_string += "CVE STATUS: Patched\n" 493 write_string += "CVE STATUS: Patched\n"
@@ -550,6 +564,8 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status):
550 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() 564 include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split()
551 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() 565 exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split()
552 566
567 report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1"
568
553 if exclude_layers and layer in exclude_layers: 569 if exclude_layers and layer in exclude_layers:
554 return 570 return
555 571
@@ -576,10 +592,11 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status):
576 592
577 for cve in sorted(cve_data): 593 for cve in sorted(cve_data):
578 is_patched = cve in patched 594 is_patched = cve in patched
595 is_ignored = cve in ignored
579 status = "Unpatched" 596 status = "Unpatched"
580 if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): 597 if (is_patched or is_ignored) and not report_all:
581 continue 598 continue
582 if cve in ignored: 599 if is_ignored:
583 status = "Ignored" 600 status = "Ignored"
584 elif is_patched: 601 elif is_patched:
585 status = "Patched" 602 status = "Patched"