diff options
Diffstat (limited to 'meta/recipes-kernel/linux/generate-cve-exclusions.py')
-rwxr-xr-x | meta/recipes-kernel/linux/generate-cve-exclusions.py | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/generate-cve-exclusions.py b/meta/recipes-kernel/linux/generate-cve-exclusions.py new file mode 100755 index 0000000000..aa9195aab4 --- /dev/null +++ b/meta/recipes-kernel/linux/generate-cve-exclusions.py @@ -0,0 +1,98 @@ +#! /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() |