#! /usr/bin/env python3 # Generate granular CVE status metadata for a specific version of the kernel # using data from linuxkernelcves.com. # # SPDX-License-Identifier: GPL-2.0-only import argparse import datetime import json import pathlib import re from packaging.version import Version def parse_version(s): """ Parse the version string and either return a packaging.version.Version, or None if the string was unset or "unk". """ if s and s != "unk": # packaging.version.Version doesn't approve of versions like v5.12-rc1-dontuse s = s.replace("-dontuse", "") return Version(s) return None def main(argp=None): parser = argparse.ArgumentParser() parser.add_argument("datadir", type=pathlib.Path, help="Path to a clone of https://github.com/nluedtke/linux_kernel_cves") parser.add_argument("version", type=Version, help="Kernel version number to generate data for, such as 6.1.38") args = parser.parse_args(argp) datadir = args.datadir version = args.version base_version = f"{version.major}.{version.minor}" with open(datadir / "data" / "kernel_cves.json", "r") as f: cve_data = json.load(f) with open(datadir / "data" / "stream_fixes.json", "r") as f: stream_data = json.load(f) print(f""" # Auto-generated CVE metadata, DO NOT EDIT BY HAND. # Generated at {datetime.datetime.now(datetime.timezone.utc)} for version {version} python check_kernel_cve_status_version() {{ this_version = "{version}" kernel_version = d.getVar("LINUX_VERSION") if kernel_version != this_version: bb.warn("Kernel CVE status needs updating: generated for %s but kernel is %s" % (this_version, kernel_version)) }} do_cve_check[prefuncs] += "check_kernel_cve_status_version" """) for cve, data in cve_data.items(): if "affected_versions" not in data: print(f"# Skipping {cve}, no affected_versions") print() continue affected = data["affected_versions"] first_affected, fixed = re.search(r"(.+) to (.+)", affected).groups() first_affected = parse_version(first_affected) fixed = parse_version(fixed) if not fixed: print(f"# {cve} has no known resolution") elif first_affected and version < first_affected: print(f'CVE_STATUS[{cve}] = "fixed-version: only affects {first_affected} onwards"') elif fixed <= version: print( f'CVE_STATUS[{cve}] = "fixed-version: Fixed from version {fixed}"' ) else: if cve in stream_data: backport_data = stream_data[cve] if base_version in backport_data: backport_ver = Version(backport_data[base_version]["fixed_version"]) if backport_ver <= version: print( f'CVE_STATUS[{cve}] = "cpe-stable-backport: Backported in {backport_ver}"' ) else: # TODO print a note that the kernel needs bumping print(f"# {cve} needs backporting (fixed from {backport_ver})") else: print(f"# {cve} needs backporting (fixed from {fixed})") else: print(f"# {cve} needs backporting (fixed from {fixed})") print() if __name__ == "__main__": main()