From 34f682a24b7075b12ec308154b937ad118d69fe5 Mon Sep 17 00:00:00 2001 From: Andrej Valek Date: Fri, 23 Jun 2023 13:14:56 +0200 Subject: cve-check: add option to add additional patched CVEs - Replace CVE_CHECK_IGNORE with CVE_STATUS to be more flexible. The CVE_STATUS should contain an information about status wich is decoded in 3 items: - generic status: "Ignored", "Patched" or "Unpatched" - more detailed status enum - description: free text describing reason for status Examples of usage: CVE_STATUS[CVE-1234-0001] = "not-applicable-platform: Issue only applies on Windows" CVE_STATUS[CVE-1234-0002] = "fixed-version: Fixed externally" CVE_CHECK_STATUSMAP[not-applicable-platform] = "Ignored" CVE_CHECK_STATUSMAP[fixed-version] = "Patched" Signed-off-by: Andrej Valek Signed-off-by: Peter Marko Signed-off-by: Richard Purdie --- meta/classes/cve-check.bbclass | 81 +++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 13 deletions(-) (limited to 'meta/classes') diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index f7abaf4f0c..c1f1ea0fd6 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass @@ -70,12 +70,28 @@ CVE_CHECK_COVERAGE ??= "1" # Skip CVE Check for packages (PN) CVE_CHECK_SKIP_RECIPE ?= "" -# Ingore the check for a given list of CVEs. If a CVE is found, -# then it is considered patched. The value is a string containing -# space separated CVE values: +# Replace NVD DB check status for a given CVE. Each of CVE has to be mentioned +# separately with optional detail and description for this status. # -# CVE_CHECK_IGNORE = 'CVE-2014-2524 CVE-2018-1234' +# CVE_STATUS[CVE-1234-0001] = "not-applicable-platform: Issue only applies on Windows" +# CVE_STATUS[CVE-1234-0002] = "fixed-version: Fixed externally" # +# Settings the same status and reason for multiple CVEs is possible +# via CVE_STATUS_GROUPS variable. +# +# CVE_STATUS_GROUPS = "CVE_STATUS_WIN CVE_STATUS_PATCHED" +# +# CVE_STATUS_WIN = "CVE-1234-0001 CVE-1234-0003" +# CVE_STATUS_WIN[status] = "not-applicable-platform: Issue only applies on Windows" +# CVE_STATUS_PATCHED = "CVE-1234-0002 CVE-1234-0004" +# CVE_STATUS_PATCHED[status] = "fixed-version: Fixed externally" +# +# All possible CVE statuses could be found in cve-check-map.conf +# CVE_CHECK_STATUSMAP[not-applicable-platform] = "Ignored" +# CVE_CHECK_STATUSMAP[fixed-version] = "Patched" +# +# CVE_CHECK_IGNORE is deprecated and CVE_STATUS has to be used instead. +# Keep CVE_CHECK_IGNORE until other layers migrate to new variables CVE_CHECK_IGNORE ?= "" # Layers to be excluded @@ -88,6 +104,24 @@ CVE_CHECK_LAYER_INCLUDELIST ??= "" # set to "alphabetical" for version using single alphabetical character as increment release CVE_VERSION_SUFFIX ??= "" +python () { + # Fallback all CVEs from CVE_CHECK_IGNORE to CVE_STATUS + cve_check_ignore = d.getVar("CVE_CHECK_IGNORE") + if cve_check_ignore: + bb.warn("CVE_CHECK_IGNORE is deprecated in favor of CVE_STATUS") + for cve in (d.getVar("CVE_CHECK_IGNORE") or "").split(): + d.setVarFlag("CVE_STATUS", cve, "ignored") + + # Process CVE_STATUS_GROUPS to set multiple statuses and optional detail or description at once + for cve_status_group in (d.getVar("CVE_STATUS_GROUPS") or "").split(): + cve_group = d.getVar(cve_status_group) + if cve_group is not None: + for cve in cve_group.split(): + d.setVarFlag("CVE_STATUS", cve, d.getVarFlag(cve_status_group, "status")) + else: + bb.warn("CVE_STATUS_GROUPS contains undefined variable %s" % cve_status_group) +} + def generate_json_report(d, out_path, link_path): if os.path.exists(d.getVar("CVE_CHECK_SUMMARY_INDEX_PATH")): import json @@ -260,7 +294,7 @@ def check_cves(d, patched_cves): """ Connect to the NVD database and find unpatched cves. """ - from oe.cve_check import Version, convert_cve_version + from oe.cve_check import Version, convert_cve_version, decode_cve_status pn = d.getVar("PN") real_pv = d.getVar("PV") @@ -282,7 +316,12 @@ def check_cves(d, patched_cves): bb.note("Recipe has been skipped by cve-check") return ([], [], [], []) - cve_ignore = d.getVar("CVE_CHECK_IGNORE").split() + # Convert CVE_STATUS into ignored CVEs and check validity + cve_ignore = [] + for cve in (d.getVarFlags("CVE_STATUS") or {}): + decoded_status, _, _ = decode_cve_status(d, cve) + if decoded_status == "Ignored": + cve_ignore.append(cve) import sqlite3 db_file = d.expand("file:${CVE_CHECK_DB_FILE}?mode=ro") @@ -413,6 +452,8 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data): CVE manifest if enabled. """ + from oe.cve_check import decode_cve_status + cve_file = d.getVar("CVE_CHECK_LOG") fdir_name = d.getVar("FILE_DIRNAME") layer = fdir_name.split("/")[-3] @@ -441,20 +482,27 @@ def cve_write_data_text(d, patched, unpatched, ignored, cve_data): is_patched = cve in patched is_ignored = cve in ignored + status = "Unpatched" if (is_patched or is_ignored) and not report_all: continue + if is_ignored: + status = "Ignored" + elif is_patched: + status = "Patched" + else: + # default value of status is Unpatched + unpatched_cves.append(cve) 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 is_ignored: - write_string += "CVE STATUS: Ignored\n" - elif is_patched: - write_string += "CVE STATUS: Patched\n" - else: - unpatched_cves.append(cve) - write_string += "CVE STATUS: Unpatched\n" + write_string += "CVE STATUS: %s\n" % status + _, detail, description = decode_cve_status(d, cve) + if detail: + write_string += "CVE DETAIL: %s\n" % detail + if description: + write_string += "CVE DESCRIPTION: %s\n" % description write_string += "CVE SUMMARY: %s\n" % cve_data[cve]["summary"] write_string += "CVSS v2 BASE SCORE: %s\n" % cve_data[cve]["scorev2"] write_string += "CVSS v3 BASE SCORE: %s\n" % cve_data[cve]["scorev3"] @@ -516,6 +564,8 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status): Prepare CVE data for the JSON format, then write it. """ + from oe.cve_check import decode_cve_status + output = {"version":"1", "package": []} nvd_link = "https://nvd.nist.gov/vuln/detail/" @@ -576,6 +626,11 @@ def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status): "status" : status, "link": issue_link } + _, detail, description = decode_cve_status(d, cve) + if detail: + cve_item["detail"] = detail + if description: + cve_item["description"] = description cve_list.append(cve_item) package_data["issue"] = cve_list -- cgit 1.2.3-korg