blob: aa9195aab4f31436423b5889da2fac9b11371f87 [file] [log] [blame]
Patrick Williams2a254922023-08-11 09:48:11 -05001#! /usr/bin/env python3
2
3# Generate granular CVE status metadata for a specific version of the kernel
4# using data from linuxkernelcves.com.
5#
6# SPDX-License-Identifier: GPL-2.0-only
7
8import argparse
9import datetime
10import json
11import pathlib
12import re
13
14from packaging.version import Version
15
16
17def parse_version(s):
18 """
19 Parse the version string and either return a packaging.version.Version, or
20 None if the string was unset or "unk".
21 """
22 if s and s != "unk":
23 # packaging.version.Version doesn't approve of versions like v5.12-rc1-dontuse
24 s = s.replace("-dontuse", "")
25 return Version(s)
26 return None
27
28
29def main(argp=None):
30 parser = argparse.ArgumentParser()
31 parser.add_argument("datadir", type=pathlib.Path, help="Path to a clone of https://github.com/nluedtke/linux_kernel_cves")
32 parser.add_argument("version", type=Version, help="Kernel version number to generate data for, such as 6.1.38")
33
34 args = parser.parse_args(argp)
35 datadir = args.datadir
36 version = args.version
37 base_version = f"{version.major}.{version.minor}"
38
39 with open(datadir / "data" / "kernel_cves.json", "r") as f:
40 cve_data = json.load(f)
41
42 with open(datadir / "data" / "stream_fixes.json", "r") as f:
43 stream_data = json.load(f)
44
Andrew Geissler5082cc72023-09-11 08:41:39 -040045 print(f"""
46# Auto-generated CVE metadata, DO NOT EDIT BY HAND.
47# Generated at {datetime.datetime.now(datetime.timezone.utc)} for version {version}
48
49python check_kernel_cve_status_version() {{
50 this_version = "{version}"
51 kernel_version = d.getVar("LINUX_VERSION")
52 if kernel_version != this_version:
53 bb.warn("Kernel CVE status needs updating: generated for %s but kernel is %s" % (this_version, kernel_version))
54}}
55do_cve_check[prefuncs] += "check_kernel_cve_status_version"
56""")
Patrick Williams2a254922023-08-11 09:48:11 -050057
58 for cve, data in cve_data.items():
59 if "affected_versions" not in data:
60 print(f"# Skipping {cve}, no affected_versions")
61 print()
62 continue
63
64 affected = data["affected_versions"]
Andrew Geissler5082cc72023-09-11 08:41:39 -040065 first_affected, fixed = re.search(r"(.+) to (.+)", affected).groups()
Patrick Williams2a254922023-08-11 09:48:11 -050066 first_affected = parse_version(first_affected)
Andrew Geissler5082cc72023-09-11 08:41:39 -040067 fixed = parse_version(fixed)
Patrick Williams2a254922023-08-11 09:48:11 -050068
Andrew Geissler5082cc72023-09-11 08:41:39 -040069 if not fixed:
Patrick Williams2a254922023-08-11 09:48:11 -050070 print(f"# {cve} has no known resolution")
71 elif first_affected and version < first_affected:
72 print(f'CVE_STATUS[{cve}] = "fixed-version: only affects {first_affected} onwards"')
Andrew Geissler5082cc72023-09-11 08:41:39 -040073 elif fixed <= version:
Patrick Williams2a254922023-08-11 09:48:11 -050074 print(
Andrew Geissler5082cc72023-09-11 08:41:39 -040075 f'CVE_STATUS[{cve}] = "fixed-version: Fixed from version {fixed}"'
Patrick Williams2a254922023-08-11 09:48:11 -050076 )
77 else:
78 if cve in stream_data:
79 backport_data = stream_data[cve]
80 if base_version in backport_data:
81 backport_ver = Version(backport_data[base_version]["fixed_version"])
Andrew Geissler5082cc72023-09-11 08:41:39 -040082 if backport_ver <= version:
Patrick Williams2a254922023-08-11 09:48:11 -050083 print(
84 f'CVE_STATUS[{cve}] = "cpe-stable-backport: Backported in {backport_ver}"'
85 )
86 else:
87 # TODO print a note that the kernel needs bumping
88 print(f"# {cve} needs backporting (fixed from {backport_ver})")
89 else:
Andrew Geissler5082cc72023-09-11 08:41:39 -040090 print(f"# {cve} needs backporting (fixed from {fixed})")
Patrick Williams2a254922023-08-11 09:48:11 -050091 else:
Andrew Geissler5082cc72023-09-11 08:41:39 -040092 print(f"# {cve} needs backporting (fixed from {fixed})")
Patrick Williams2a254922023-08-11 09:48:11 -050093
94 print()
95
96
97if __name__ == "__main__":
98 main()