From patchwork Fri Apr 17 13:24:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Turull X-Patchwork-Id: 86384 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A40BBF436A1 for ; Fri, 17 Apr 2026 13:24:21 +0000 (UTC) Received: from AS8PR04CU009.outbound.protection.outlook.com (AS8PR04CU009.outbound.protection.outlook.com [52.101.70.68]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.44942.1776432259588381154 for ; Fri, 17 Apr 2026 06:24:20 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@ericsson.com header.s=selector1 header.b=zEUfYtz+; spf=pass (domain: ericsson.com, ip: 52.101.70.68, mailfrom: edaturu@ericsson.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=CBai93GFQAAtRA/cVtGH7g3iWKincTbeNtKiue3y33QuxA9QnoR9M1BFIPOy/b19YslIG+4zUwVPpHDHBI1HoOnhoffrlQtmovOTDjGLavGatxlXPeofJVYdxX04BZBXJHSudHAQ9tuItxT214SpFBIVs7LDgIJElr4GMfVkZqtE/kC154alvdjE49gcwx0LGWW/Ogx6in060tPpYjl4N5q8tl1G12N2wSTSKOdMHurHgGcL8FDt20i6JZh4FqnCZjicZ2jywgYBkm8103QwYXxRTIvWrv9iqedMLrLraMZGvgsB/iKuyfx7Y7brPWvYkIYOLlOWPOYJnuV2SSLNGA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=gpFjwPXWXb+xtAP69Q63W/OgLI2FVYALr9Bah+HfGRs=; b=mxIrOFtxBOBZkz5K+Bsd9SMl68sZKQgU8z5aHQ9jFmucjmKh//DimyHBtII/5ZQgl2QbEKJNvrIvbWQeh/1f1LqYe7R6iJRcGsFJWRuo7w0zwctI/xeT6VmVQdNPOiNPtAHf3UBbsbhUOir1B1XVe59DALpR3OYDmTTHbo49bS7uAGh3nxIdfdKl5OoHVq6zgGMj1AW+cPkZPGzwnvG3oCvnfU2JgNVj2b7Z4E2isw9KUU5axU94VYeZqS5T7LCZfcaKgnJUvjmERiOxSwiPylpXxBCmGJSleOhaBso+Il+uNINsFIt5tILiG0yHT6POyrx+l38fOGUrhgQ6j3HUZA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 192.176.1.74) smtp.rcpttodomain=bootlin.com smtp.mailfrom=ericsson.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ericsson.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ericsson.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=gpFjwPXWXb+xtAP69Q63W/OgLI2FVYALr9Bah+HfGRs=; b=zEUfYtz+dlGWOhuoiOEymhYZMDDLqv25GswX6V7t1TcdRTe8hleTrB1CNzMCnVt5zz9vgl0zm4axIWDzusMjvcpngjlIEUq5BR5L8oHabhiiSdp4FWhupI/LSm8O3VDE+0qGIHNDVdZIW9jop9xm9mBMo0jejuB7rRy93aIImGt7JvzBV5rWW4RXpKFIZM4PnzrQUkzyRVi0c4G1/t4LKY29Lnoen5qm6DDW7janhy6/BhXq3nPzk86hHa1fCPdGY8JSZYnRp60MOTXfEjL15HLDaCpCVm+phfLK7f84EUXufahaLEIl7eqnS9kyxn0u9rjvxmoF9HTrG5CViXKQVw== Received: from DU7P251CA0012.EURP251.PROD.OUTLOOK.COM (2603:10a6:10:551::18) by AMVPR07MB12305.eurprd07.prod.outlook.com (2603:10a6:20b:775::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9818.21; Fri, 17 Apr 2026 13:24:14 +0000 Received: from DB5PEPF00014B8D.eurprd02.prod.outlook.com (2603:10a6:10:551:cafe::d1) by DU7P251CA0012.outlook.office365.com (2603:10a6:10:551::18) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.52 via Frontend Transport; Fri, 17 Apr 2026 13:24:14 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 192.176.1.74) smtp.mailfrom=ericsson.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ericsson.com; Received-SPF: Pass (protection.outlook.com: domain of ericsson.com designates 192.176.1.74 as permitted sender) receiver=protection.outlook.com; client-ip=192.176.1.74; helo=oa.msg.ericsson.com; pr=C Received: from oa.msg.ericsson.com (192.176.1.74) by DB5PEPF00014B8D.mail.protection.outlook.com (10.167.8.201) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17 via Frontend Transport; Fri, 17 Apr 2026 13:24:13 +0000 Received: from seroius18814.sero.gic.ericsson.se (153.88.142.248) by smtp-central.internal.ericsson.com (100.87.178.68) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.29; Fri, 17 Apr 2026 15:24:13 +0200 Received: from seroius08462.sero.gic.ericsson.se (seroius08462.sero.gic.ericsson.se [10.63.237.245]) by seroius18814.sero.gic.ericsson.se (Postfix) with ESMTP id 393A44020B70; Fri, 17 Apr 2026 15:24:13 +0200 (CEST) Received: by seroius08462.sero.gic.ericsson.se (Postfix, from userid 160155) id 22E30700CF09; Fri, 17 Apr 2026 15:24:13 +0200 (CEST) From: To: CC: , Daniel Turull Subject: [PATCH] improve_kernel_cve_report: use numeric versions instead of cpeApplicability Date: Fri, 17 Apr 2026 15:24:09 +0200 Message-ID: <20260417132409.1638132-1-daniel.turull@ericsson.com> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DB5PEPF00014B8D:EE_|AMVPR07MB12305:EE_ X-MS-Office365-Filtering-Correlation-Id: dc4a263f-2ca1-4a93-7fde-08de9c849e61 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|82310400026|36860700016|376014|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: OswJqFWRBf58Zbuk27Qgs9Fd4TUr6mszpnl1ENUCRqwDaEtd0TlTIyiHLtE+YWu8c456YrGP4Tz0mkIRuFVQYI8bJaO4uPtaZfNkEC4ma4W4d5DyZFRrEx2JDbvMn9rwKP9Isa3RuAW60NdSDILeUDiNGKdY85fXiwX8Qm1HXG1rZHBNZiBhCbBPjkF2eh8Yo2ePfBlI1MdHU7QdHDuGKClf9Gz0dEUQSs+dKiOE7+p4GBDmv1qqIWAJ7wyaEg7JY9MEpcr+M0xYKtpuUDG+bZIdJKuSmgD5uFYRt2fuBGwq/qGjsV+VwbzVQt7p5zc48NLVUtInHBCd6Q+c7rrZnW08Y1cUzJ3Ei3O9qvHppl6QpwR4y1KU372to4pVhy67L6gfr65KA7J9NVw00rNmtBBrBuFozoCca4cWMr8xaoQSh5+gdyuVr5ujZClZZ8/MGRtgIKK5M0cjCcqzHgGWLAWq44YB6l31jxy4W3ZdUv5X6uvPMOcImKpKdvA3qSOEaMaXw+tv5HD5EiwTeR7Z2dB4G81f7z+W6Ef+PpZnS5Dk+DZCx7yXDQbv87blHgtnarHFnK9Pkfm4lRt3lWRA2UlGKblDB/wh3tOwghgZbchptXxoR24DCLqqfom9FyaQtP8R14JB6BJd+P9JYUaq8VGmptsVDrg4wuR0eYYevfQjZaQz1V86bdc71ogPW5gr3iP1TUc7WpxeFFz1aT4Rg03OYNwnF59Rzcl6Sj72iClcKO8WDIASIEPZ6h1R3WH8fKT/JrIW1kGZBmt4YHsSvw== X-Forefront-Antispam-Report: CIP:192.176.1.74;CTRY:SE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:oa.msg.ericsson.com;PTR:office365.se.ericsson.net;CAT:NONE;SFS:(13230040)(1800799024)(82310400026)(36860700016)(376014)(18002099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: iD8U1T2GCmY60/x1L1X42pmLxbFLbiSkcKH0mV9Mf1muVs5C5z0mPSmae2pQ+K5zvIhhn/r6SIaB92fKVDDTCJz6B6UrUQzvpr9J1YwoJtB2SE+xWJtCpHDecgryJ9/5Kcm02BGfMWvVeovfFoeURigdoD6jA0k/ItLD9bWibV+DgZqoxMKtG1bebIFVGvV7zawMI9BMTDiutuy+HZ21X6DkOFzOg7lijgYJD+Y1egUjqrzC7IUv4K7Ya0h1RZxUyUi3NilIVRHvE8ug5kbwRG1lzwqF8sbrFmVBjDxHD2JDttgt7LhWzh/E9SwO7bUUfe4f8vRUHc5VKqw0+peDttm9vUfQR9eAjg8L6pn4K0+Rt5+gDO8yfZTv58U/+hzZ8GDx8b8dEKqK99v+UFfmJhNWf+2DU/KgZka6I38zXd/hijYT2Fqe6hSUtkIFmBDS X-OriginatorOrg: ericsson.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Apr 2026 13:24:13.9181 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: dc4a263f-2ca1-4a93-7fde-08de9c849e61 X-MS-Exchange-CrossTenant-Id: 92e84ceb-fbfd-47ab-be52-080c6b87953f X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=92e84ceb-fbfd-47ab-be52-080c6b87953f;Ip=[192.176.1.74];Helo=[oa.msg.ericsson.com] X-MS-Exchange-CrossTenant-AuthSource: DB5PEPF00014B8D.eurprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AMVPR07MB12305 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 17 Apr 2026 13:24:21 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/235499 From: Daniel Turull git shas or versions should be use instead of cpeApplicability. Reuse the same logic as generate-cve-exclusions, so outputs are consistent. cpeApplicability does not provide accurate version information and for some CVEs the information is not the same. This came from a discussion that we had with Greg Kroah-Hartma, member of the Linux security team. Signed-off-by: Daniel Turull --- scripts/contrib/improve_kernel_cve_report.py | 247 ++++++++----------- 1 file changed, 104 insertions(+), 143 deletions(-) diff --git a/scripts/contrib/improve_kernel_cve_report.py b/scripts/contrib/improve_kernel_cve_report.py index b386c9383a..a5458f8dd3 100755 --- a/scripts/contrib/improve_kernel_cve_report.py +++ b/scripts/contrib/improve_kernel_cve_report.py @@ -82,16 +82,59 @@ def get_kernel_cves(datadir, compiled_files, version): "description": f"Rejected by CNA" } continue - if any(elem in cve_file for elem in ["review", "reverved", "testing"]): + if any(elem in cve_file for elem in ["review", "reverved", "testing", "tmp"]): continue - is_vulnerable, first_affected, last_affected, better_match_first, better_match_last, affected_versions = get_cpe_applicability(cve_info, version) + first_affected, fixed, backport_ver = get_fixed_versions(cve_info, base_version) - logging.debug("%s: %s (%s - %s) (%s - %s)", cve_id, is_vulnerable, better_match_first, better_match_last, first_affected, last_affected) + logging.debug("%s: first_affected=%s fixed=%s backport=%s", cve_id, first_affected, fixed, backport_ver) - if is_vulnerable is None: - logging.warning("%s doesn't have good metadata", cve_id) - if is_vulnerable: + if not fixed: + logging.warning("%s has no known resolution", cve_id) + cves[cve_id] = { + "id": cve_id, + "status": "Unpatched", + "detail": "known-affected", + "summary": description, + "description": "No known resolution" + } + vulnerable += 1 + continue + elif first_affected and version < first_affected: + logging.debug('%s - fixed-version: only affects %s onwards', + cve_id, first_affected) + cves[cve_id] = { + "id": cve_id, + "status": "Patched", + "detail": "fixed-version", + "summary": description, + "description": f"only affects {first_affected} onwards" + } + not_vulnerable += 1 + elif fixed <= version: + logging.debug("%s - fixed-version: Fixed from version %s", + cve_id, fixed) + cves[cve_id] = { + "id": cve_id, + "status": "Patched", + "detail": "fixed-version", + "summary": description, + "description": f"Fixed from version {fixed}" + } + not_vulnerable += 1 + elif backport_ver and backport_ver <= version: + logging.debug("%s - cpe-stable-backport: Backported in %s", + cve_id, backport_ver) + cves[cve_id] = { + "id": cve_id, + "status": "Patched", + "detail": "cpe-stable-backport", + "summary": description, + "description": f"Backported in {backport_ver}" + } + not_vulnerable += 1 + else: + # Vulnerable - may need backporting is_affected = True affected_files = [] if check_config: @@ -108,87 +151,21 @@ def get_kernel_cves(datadir, compiled_files, version): "summary": description, "description": f"Source code not compiled by config. {sorted(affected_files)}" } - not_applicable_config +=1 - # Check if we have backport + not_applicable_config += 1 else: - if not better_match_last: - fixed_in = last_affected - else: - fixed_in = better_match_last + fixed_in = backport_ver if backport_ver else fixed logging.debug("%s needs backporting (fixed from %s)", cve_id, fixed_in) - cves[cve_id] = { - "id": cve_id, - "status": "Unpatched", - "detail": "version-in-range", - "summary": description, - "description": f"Needs backporting (fixed from {fixed_in})" - } - vulnerable += 1 - if (better_match_last and - Version(f"{better_match_last.major}.{better_match_last.minor}") == base_version): - fixed_as_later_backport += 1 - # Not vulnerable - else: - if not first_affected: - logging.debug("%s - not known affected %s", - cve_id, - better_match_last) cves[cve_id] = { "id": cve_id, - "status": "Patched", - "detail": "version-not-in-range", + "status": "Unpatched", + "detail": "version-in-range", "summary": description, - "description": "No CPE match" + "description": f"Needs backporting (fixed from {fixed_in})" } - not_vulnerable += 1 - continue - backport_base = Version(f"{better_match_last.major}.{better_match_last.minor}") - if version < first_affected: - logging.debug('%s - fixed-version: only affects %s onwards', - cve_id, - first_affected) - cves[cve_id] = { - "id": cve_id, - "status": "Patched", - "detail": "fixed-version", - "summary": description, - "description": f"only affects {first_affected} onwards" - } - not_vulnerable += 1 - elif last_affected <= version: - logging.debug("%s - fixed-version: Fixed from version %s", - cve_id, - last_affected) - cves[cve_id] = { - "id": cve_id, - "status": "Patched", - "detail": "fixed-version", - "summary": description, - "description": f"Fixed from version {last_affected}" - } - not_vulnerable += 1 - elif backport_base == base_version: - logging.debug("%s - cpe-stable-backport: Backported in %s", - cve_id, - better_match_last) - cves[cve_id] = { - "id": cve_id, - "status": "Patched", - "detail": "cpe-stable-backport", - "summary": description, - "description": f"Backported in {better_match_last}" - } - not_vulnerable += 1 - else: - logging.debug("%s - version not affected %s", cve_id, str(affected_versions)) - cves[cve_id] = { - "id": cve_id, - "status": "Patched", - "detail": "version-not-in-range", - "summary": description, - "description": f"Range {affected_versions}" - } - not_vulnerable += 1 + vulnerable += 1 + if (backport_ver and + Version(f"{backport_ver.major}.{backport_ver.minor}") == base_version): + fixed_as_later_backport += 1 logging.info("Total CVEs ignored due to not applicable config: %d", not_applicable_config) logging.info("Total CVEs not vulnerable due version-not-in-range: %d", not_vulnerable) @@ -276,70 +253,54 @@ def check_kernel_compiled_files(compiled_files, cve_info): is_affected = True return is_affected, files_affected -def get_cpe_applicability(cve_info, v): +def get_fixed_versions(cve_info, base_version): ''' - Check if version is affected and return affected versions + Get fixed versionss ''' - base_branch = Version(f"{v.major}.{v.minor}") - affected = [] - if not 'cpeApplicability' in cve_info["containers"]["cna"]: - return None, None, None, None, None, None - - for nodes in cve_info["containers"]["cna"]["cpeApplicability"]: - for node in nodes.values(): - vulnerable = False - matched_branch = False - first_affected = Version("5000") - last_affected = Version("0") - better_match_first = Version("0") - better_match_last = Version("5000") - - if len(node[0]['cpeMatch']) == 0: - first_affected = None - last_affected = None - better_match_first = None - better_match_last = None - - for cpe_match in node[0]['cpeMatch']: - version_start_including = Version("0") - version_end_excluding = Version("0") - if 'versionStartIncluding' in cpe_match: - version_start_including = Version(cpe_match['versionStartIncluding']) - else: - version_start_including = Version("0") - # if versionEndExcluding is missing we are in a branch, which is not fixed. - if "versionEndExcluding" in cpe_match: - version_end_excluding = Version(cpe_match["versionEndExcluding"]) - else: - # if versionEndExcluding is missing we are in a branch, which is not fixed. - version_end_excluding = Version( - f"{version_start_including.major}.{version_start_including.minor}.5000" - ) - affected.append(f" {version_start_including}-{version_end_excluding}") - # Detect if versionEnd is in fixed in base branch. It has precedence over the rest - branch_end = Version(f"{version_end_excluding.major}.{version_end_excluding.minor}") - if branch_end == base_branch: - if version_start_including <= v < version_end_excluding: - vulnerable = cpe_match['vulnerable'] - # If we don't match in our branch, we are not vulnerable, - # since we have a backport - matched_branch = True - better_match_first = version_start_including - better_match_last = version_end_excluding - if version_start_including <= v < version_end_excluding and not matched_branch: - if version_end_excluding < better_match_last: - better_match_first = max(version_start_including, better_match_first) - better_match_last = min(better_match_last, version_end_excluding) - vulnerable = cpe_match['vulnerable'] - matched_branch = True - - first_affected = min(version_start_including, first_affected) - last_affected = max(version_end_excluding, last_affected) - # Not a better match, we use the first and last affected instead of the fake .5000 - if vulnerable and better_match_last == Version(f"{base_branch}.5000"): - better_match_last = last_affected - better_match_first = first_affected - return vulnerable, first_affected, last_affected, better_match_first, better_match_last, affected + first_affected = None + fixed = None + fixed_backport = None + next_version = Version(str(base_version) + ".5000") + for affected in cve_info["containers"]["cna"]["affected"]: + # In case the CVE info is not complete, it might not have default status and therefore + # we don't know the status of this CVE. + if not "defaultStatus" in affected: + return first_affected, fixed, fixed_backport + if affected["defaultStatus"] == "affected": + for version in affected["versions"]: + v = Version(version["version"]) + if v == Version('0'): + #Skiping non-affected + continue + if version["status"] == "unaffected" and first_affected and v < first_affected: + first_affected = Version(f"{v.major}.{v.minor}") + if version["status"] == "affected" and not first_affected: + first_affected = v + elif (version["status"] == "unaffected" and + version['versionType'] == "original_commit_for_fix"): + fixed = v + elif base_version < v and v < next_version: + fixed_backport = v + elif affected["defaultStatus"] == "unaffected": + # Only specific versions are affected. We care only about our base version + if "versions" not in affected: + continue + for version in affected["versions"]: + if "versionType" not in version: + continue + if version["versionType"] == "git": + continue + v = Version(version["version"]) + # in case it is not in our base version + less_than = Version(version["lessThan"]) + + if not first_affected: + first_affected = v + fixed = less_than + if base_version < v and v < next_version: + fixed_backport = less_than + + return first_affected, fixed, fixed_backport def copy_data(old, new): '''Update dictionary with new entries, while keeping the old ones'''