diff options
Diffstat (limited to 'meta/classes/cve-check.bbclass')
-rw-r--r-- | meta/classes/cve-check.bbclass | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index f574f5daa4..78516d0bb6 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass @@ -55,6 +55,9 @@ CVE_CHECK_FORMAT_TEXT ??= "1" # Provide JSON output CVE_CHECK_FORMAT_JSON ??= "1" +# Check for packages without CVEs (no issues or missing product name) +CVE_CHECK_COVERAGE ??= "1" + # Skip CVE Check for packages (PN) CVE_CHECK_SKIP_RECIPE ?= "" @@ -114,10 +117,10 @@ python do_cve_check () { patched_cves = get_patched_cves(d) except FileNotFoundError: bb.fatal("Failure in searching patches") - ignored, patched, unpatched = check_cves(d, patched_cves) - if patched or unpatched: + ignored, 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_write_data(d, patched, unpatched, ignored, cve_data) + cve_write_data(d, patched, unpatched, ignored, cve_data, status) else: bb.note("No CVE database found, skipping CVE check") @@ -207,17 +210,19 @@ def check_cves(d, patched_cves): suffix = d.getVar("CVE_VERSION_SUFFIX") cves_unpatched = [] + cves_status = [] + cves_in_recipe = False # CVE_PRODUCT can contain more than one product (eg. curl/libcurl) products = d.getVar("CVE_PRODUCT").split() # If this has been unset then we're not scanning for CVEs here (for example, image recipes) if not products: - return ([], [], []) + return ([], [], [], {}) pv = d.getVar("CVE_VERSION").split("+git")[0] # If the recipe has been skipped/ignored we return empty lists if pn in d.getVar("CVE_CHECK_SKIP_RECIPE").split(): bb.note("Recipe has been skipped by cve-check") - return ([], [], []) + return ([], [], [], []) cve_ignore = d.getVar("CVE_CHECK_IGNORE").split() @@ -227,6 +232,7 @@ def check_cves(d, patched_cves): # For each of the known product names (e.g. curl has CPEs using curl and libcurl)... for product in products: + cves_in_product = False if ":" in product: vendor, product = product.split(":", 1) else: @@ -244,6 +250,11 @@ def check_cves(d, patched_cves): elif cve in patched_cves: bb.note("%s has been patched" % (cve)) continue + # Write status once only for each product + if not cves_in_product: + cves_status.append([product, True]) + cves_in_product = True + cves_in_recipe = True vulnerable = False for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): @@ -290,9 +301,16 @@ def check_cves(d, patched_cves): # TODO: not patched but not vulnerable patched_cves.add(cve) + if not cves_in_product: + bb.note("No CVE records found for product %s, pn %s" % (product, pn)) + cves_status.append([product, False]) + conn.close() - return (list(cve_ignore), list(patched_cves), cves_unpatched) + if not cves_in_recipe: + bb.note("No CVE records for products in recipe %s" % (pn)) + + return (list(cve_ignore), list(patched_cves), cves_unpatched, cves_status) def get_cve_info(d, cves): """ @@ -323,7 +341,6 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data): CVE manifest if enabled. """ - cve_file = d.getVar("CVE_CHECK_LOG") fdir_name = d.getVar("FILE_DIRNAME") layer = fdir_name.split("/")[-3] @@ -337,6 +354,10 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data): if include_layers and layer not in include_layers: return + # Early exit, the text format does not report packages without CVEs + if not patched+unpatched: + return + nvd_link = "https://nvd.nist.gov/vuln/detail/" write_string = "" unpatched_cves = [] @@ -414,7 +435,7 @@ def cve_check_write_json_output(d, output, direct_file, deploy_file, manifest_fi with open(index_path, "a+") as f: f.write("%s\n" % fragment_path) -def cve_write_data_json(d, patched, unpatched, ignored, cve_data): +def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status): """ Prepare CVE data for the JSON format, then write it. """ @@ -436,11 +457,19 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data): unpatched_cves = [] + product_data = [] + for s in cve_status: + p = {"product": s[0], "cvesInRecord": "Yes"} + if s[1] == False: + p["cvesInRecord"] = "No" + product_data.append(p) + package_version = "%s%s" % (d.getVar("EXTENDPE"), d.getVar("PV")) package_data = { "name" : d.getVar("PN"), "layer" : layer, - "version" : package_version + "version" : package_version, + "products": product_data } cve_list = [] @@ -479,7 +508,7 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data): cve_check_write_json_output(d, output, direct_file, deploy_file, manifest_file) -def cve_write_data(d, patched, unpatched, ignored, cve_data): +def cve_write_data(d, patched, unpatched, ignored, cve_data, status): """ Write CVE data in each enabled format. """ @@ -487,4 +516,4 @@ def cve_write_data(d, patched, unpatched, ignored, cve_data): if d.getVar("CVE_CHECK_FORMAT_TEXT") == "1": cve_write_data_text(d, patched, unpatched, ignored, cve_data) if d.getVar("CVE_CHECK_FORMAT_JSON") == "1": - cve_write_data_json(d, patched, unpatched, ignored, cve_data) + cve_write_data_json(d, patched, unpatched, ignored, cve_data, status) |