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 CVE_CHECK_COPY_FILES ??= "1" CVE_CHECK_CREATE_MANIFEST ??= "1" +# Report Patched or Ignored/Whitelisted CVEs CVE_CHECK_REPORT_PATCHED ??= "1" + CVE_CHECK_SHOW_WARNINGS ??= "1" # Provide text output @@ -142,7 +144,7 @@ python do_cve_check () { bb.fatal("Failure in searching patches") whitelisted, patched, unpatched, status = check_cves(d, patched_cves) if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" and status): - cve_data = get_cve_info(d, patched + unpatched) + cve_data = get_cve_info(d, patched + unpatched + whitelisted) cve_write_data(d, patched, unpatched, whitelisted, cve_data, status) else: bb.note("No CVE database found, skipping CVE check") @@ -315,6 +317,7 @@ def check_cves(d, patched_cves): suffix = d.getVar("CVE_VERSION_SUFFIX") cves_unpatched = [] + cves_ignored = [] cves_status = [] cves_in_recipe = False # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) @@ -349,8 +352,7 @@ def check_cves(d, patched_cves): if cve in cve_whitelist: bb.note("%s-%s has been whitelisted for %s" % (product, pv, cve)) - # TODO: this should be in the report as 'whitelisted' - patched_cves.add(cve) + cves_ignored.append(cve) continue elif cve in patched_cves: bb.note("%s has been patched" % (cve)) @@ -362,9 +364,13 @@ def check_cves(d, patched_cves): cves_in_recipe = True vulnerable = False + ignored = False + for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): (_, _, _, version_start, operator_start, version_end, operator_end) = row #bb.debug(2, "Evaluating row " + str(row)) + if cve in cve_whitelist: + ignored = True if (operator_start == '=' and pv == version_start) or version_start == '-': vulnerable = True @@ -397,13 +403,16 @@ def check_cves(d, patched_cves): vulnerable = vulnerable_start or vulnerable_end if vulnerable: - bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve)) - cves_unpatched.append(cve) + if ignored: + bb.note("%s is ignored in %s-%s" % (cve, pn, real_pv)) + cves_ignored.append(cve) + else: + bb.note("%s-%s is vulnerable to %s" % (pn, real_pv, cve)) + cves_unpatched.append(cve) break if not vulnerable: bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve)) - # TODO: not patched but not vulnerable patched_cves.add(cve) if not cves_in_product: @@ -412,7 +421,7 @@ def check_cves(d, patched_cves): conn.close() - return (list(cve_whitelist), list(patched_cves), cves_unpatched, cves_status) + return (list(cves_ignored), list(patched_cves), cves_unpatched, cves_status) def get_cve_info(d, cves): """ @@ -450,6 +459,8 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data): include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() + report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1" + if exclude_layers and layer in exclude_layers: return @@ -457,7 +468,7 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data): return # Early exit, the text format does not report packages without CVEs - if not patched+unpatched: + if not patched+unpatched+whitelisted: return nvd_link = "https://nvd.nist.gov/vuln/detail/" @@ -467,13 +478,16 @@ def cve_write_data_text(d, patched, unpatched, whitelisted, cve_data): for cve in sorted(cve_data): is_patched = cve in patched - if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): + is_ignored = cve in whitelisted + + if (is_patched or is_ignored) and not report_all: continue + write_string += "LAYER: %s\n" % layer write_string += "PACKAGE NAME: %s\n" % d.getVar("PN") write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"), d.getVar("PV")) write_string += "CVE: %s\n" % cve - if cve in whitelisted: + if is_ignored: write_string += "CVE STATUS: Whitelisted\n" elif is_patched: write_string += "CVE STATUS: Patched\n" @@ -550,6 +564,8 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status): include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() + report_all = d.getVar("CVE_CHECK_REPORT_PATCHED") == "1" + if exclude_layers and layer in exclude_layers: return @@ -576,10 +592,11 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status): for cve in sorted(cve_data): is_patched = cve in patched + is_ignored = cve in ignored status = "Unpatched" - if is_patched and (d.getVar("CVE_CHECK_REPORT_PATCHED") != "1"): + if (is_patched or is_ignored) and not report_all: continue - if cve in ignored: + if is_ignored: status = "Ignored" elif is_patched: status = "Patched"