diff --git a/support/scripts/cve-check b/support/scripts/cve-check index 4d01fa5f23..af0971d06d 100755 --- a/support/scripts/cve-check +++ b/support/scripts/cve-check @@ -175,55 +175,54 @@ def nvd_cve_to_cdx_vulnerability(nvd_cve): def vuln_append_or_update_affects_if_exists(vulnerabilities, vulnerability): """ - Append 'vulnerability' passed as argument to the 'vulnerabilities' argument - if an entry with the same 'id' doesn't exist yet. - If the vulnerability already exists, the input reference is added to the - 'affects' list of the existing entry. + Updates a matching 'vulnerability' from the 'vulnerabilities' list or + appends it as a new entry. + + A vulnerability is considered 'matching' if it shares the same 'id' AND + either: + + 1. An identical 'affects' entry. + 2. An identical 'analysis.state'. Args: vulnerabilities (list): The vulnerabilities array reference retrieved from the input CycloneDX SBOM vulnerability (dict): Vulnerability to add to the 'vulnerabilities' list. """ - # Search if a vulnerability with the same identifier already exists in the - # SBOM vulnerability list. - matching_vuln = next( - (vuln for vuln in vulnerabilities if vuln.get("id") == vulnerability["id"]), - None - ) + new_analysis = vulnerability.get("analysis", {}).get("state") + new_ref = next((a.get("ref") for a in vulnerability.get("affects", [])), None) - # bom-ref to the component is passed to the affects of the vulnerability - # passed as argument - bom_ref = next((a["ref"] for a in vulnerability.get("affects", [])), None) + # All vulnerabilities with same ID + matching_vulns = [v for v in vulnerabilities if v.get("id") == vulnerability.get("id")] - if matching_vuln is not None: - # Remove the affect to not use it while updating matching vuln. - if "affects" in vulnerability: - del vulnerability["affects"] + for curr_vuln in matching_vulns: + curr_vuln_analysis = curr_vuln.get("analysis", {}).get("state") + curr_vuln_refs = [a.get("ref") for a in curr_vuln.get("affects", [])] - if matching_vuln.get("analysis") is not None and "analysis" in vulnerability: - # We don't update vulnerabilities that already have an - # 'analysis'. - # Buildroot ignored vulnerabilities will already have - # an analysis and need to remain as such. + is_same_ref = new_ref in curr_vuln_refs + is_same_analysis = curr_vuln_analysis == new_analysis + + if not (is_same_ref or is_same_analysis): + continue + + if is_same_ref: + # If same vulnerability id and same affect ref, keep the previous + # analysis. This is the case where a vulnerability was ignored from + # the generated SBOM. del vulnerability["analysis"] + del vulnerability["affects"] + else: + # The same analysis, add a new affect + # reference. + if new_ref is not None: + curr_vuln.setdefault("affects", []).append({"ref": new_ref}) + del vulnerability["affects"] - affects = matching_vuln.setdefault("affects", []) + curr_vuln.update(vulnerability) + return - if bom_ref is not None: - ref = next((a["ref"] for a in affects if a["ref"] == bom_ref), None) - if ref is None: - # Add a 'ref' (bom reference) to the component if not - # already present in the 'affects' list. - affects.append({ - "ref": bom_ref - }) - - # Update the metadata of the vulnerability with the one - # downloaded from the database. - matching_vuln.update(vulnerability) - else: - vulnerabilities.append(vulnerability) + # No same ID w/ same analysis or same ref. + vulnerabilities.append(vulnerability) def check_package_cve_affects(cve: cvecheck.CVE, cpe_product_pkgs, sbom, opt: Options): @@ -297,8 +296,7 @@ def enrich_vulnerabilities(nvd_path: Path, sbom): print(f"Warning: '{vuln_id}' doesn't exist in NVD database.", file=sys.stderr) continue - vulnerability = nvd_cve_to_cdx_vulnerability(cve.nvd_cve) - vuln_append_or_update_affects_if_exists(vulnerabilities, vulnerability) + vuln.update(nvd_cve_to_cdx_vulnerability(cve.nvd_cve)) def main():