@@ -91,19 +91,38 @@ def main(argp=None):
parser = argparse.ArgumentParser()
parser.add_argument("datadir", type=pathlib.Path, help="Path to a clone of https://github.com/CVEProject/cvelistV5 or https://git.kernel.org/pub/scm/linux/security/vulns.git")
parser.add_argument("version", type=Version, help="Kernel version number to generate data for, such as 6.1.38")
+ parser.add_argument("--output-json-file", type=pathlib.Path, help="Write CVE_STATUS mapping to this JSON file")
+ parser.add_argument("--output-inc-file", type=pathlib.Path, help="Write CVE_STATUS mapping to this INC file")
args = parser.parse_args(argp)
datadir = args.datadir.resolve()
version = args.version
base_version = Version(f"{version.major}.{version.minor}")
-
- data_version = subprocess.check_output(("git", "describe", "--tags", "HEAD"), cwd=datadir, text=True)
-
- print(f"""
+ print_to_stdout = not args.output_json_file and not args.output_inc_file
+
+ cve_status = {}
+ inc_lines = []
+
+ if print_to_stdout:
+ data_version = subprocess.check_output(("git", "describe", "--tags", "HEAD"), cwd=datadir, text=True)
+ print(f"""
# Auto-generated CVE metadata, DO NOT EDIT BY HAND.
# Generated at {datetime.datetime.now(datetime.timezone.utc)} for kernel version {version}
# From {datadir.name} {data_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"
+""")
+ elif args.output_inc_file:
+ inc_lines.append(f"""
+# Auto-generated CVE metadata, DO NOT EDIT BY HAND.
+# Generated at {datetime.datetime.now(datetime.timezone.utc)} for kernel version {version}
+
python check_kernel_cve_status_version() {{
this_version = "{version}"
kernel_version = d.getVar("LINUX_VERSION")
@@ -131,26 +150,80 @@ do_cve_check[prefuncs] += "check_kernel_cve_status_version"
continue
first_affected, fixed, backport_ver = get_fixed_versions(cve_info, base_version)
if not fixed:
- print(f"# {cve} has no known resolution")
+ cve_status[cve] = {
+ "active": True,
+ "message": "no known resolution"
+ }
+ if not args.output_json_file:
+ print(f"# {cve} has no known resolution")
+ elif args.output_inc_file:
+ inc_lines.append(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"')
+ cve_status[cve] = {
+ "active": False,
+ "message": f"fixed-version: only affects {first_affected} onwards"
+ }
+ if not args.output_json_file:
+ print(f'CVE_STATUS[{cve}] = "fixed-version: only affects {first_affected} onwards"')
+ elif args.output_inc_file:
+ inc_lines.append(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}"'
- )
+ cve_status[cve] = {
+ "active": False,
+ "message": f"fixed-version: Fixed from version {fixed}"
+ }
+ if not args.output_json_file:
+ print(f'CVE_STATUS[{cve}] = "fixed-version: Fixed from version {fixed}"')
+ elif args.output_inc_file:
+ inc_lines.append(f'CVE_STATUS[{cve}] = "fixed-version: Fixed from version {fixed}"')
else:
if backport_ver:
if backport_ver <= version:
- print(
- f'CVE_STATUS[{cve}] = "cpe-stable-backport: Backported in {backport_ver}"'
- )
+ cve_status[cve] = {
+ "active": False,
+ "message": f"cpe-stable-backport: Backported in {backport_ver}"
+ }
+ if not args.output_json_file:
+ print(f'CVE_STATUS[{cve}] = "cpe-stable-backport: Backported in {backport_ver}"')
+ elif args.output_inc_file:
+ inc_lines.append(f'CVE_STATUS[{cve}] = "cpe-stable-backport: Backported in {backport_ver}"')
else:
- print(f"# {cve} may need backporting (fixed from {backport_ver})")
+ cve_status[cve] = {
+ "active": True,
+ "message": f"May need backporting (fixed from {backport_ver})"
+ }
+ if not args.output_json_file:
+ print(f"# {cve} may need backporting (fixed from {backport_ver})")
+ elif args.output_inc_file:
+ inc_lines.append(f'# {cve} may need backporting (fixed from {backport_ver})')
else:
- print(f"# {cve} needs backporting (fixed from {fixed})")
-
- print()
-
+ cve_status[cve] = {
+ "active": True,
+ "message": f"#Needs backporting (fixed from {fixed})"
+ }
+ if not args.output_json_file:
+ print(f"# {cve} needs backporting (fixed from {fixed})")
+ elif args.output_inc_file:
+ inc_lines.append(f'# {cve} needs backporting (fixed from {fixed})')
+
+ if print_to_stdout:
+ print()
+ elif args.output_inc_file:
+ inc_lines.append("")
+
+ # Emit structured output if --ret-struct was requested
+ if args.output_json_file:
+ args.output_json_file.write_text(
+ json.dumps(
+ {
+ "cve_status": cve_status,
+ },
+ indent=2
+ ),
+ encoding="utf-8"
+ )
+ if args.output_inc_file:
+ args.output_inc_file.write_text("\n".join(inc_lines), encoding="utf-8")
if __name__ == "__main__":
main()
This option "--output-json-file" can be used to return a json file instead of the printing the output in a .inc file. The JSON file can easily be manipulated contrary to the .inc file. Example output structure of the JSON file: ```json { "cve_status": { "CVE-2019-25160": { "active": false, "message": "fixed-version: Fixed from version 5.0" }, "CVE-2019-25162": { "active": false, "message": "fixed-version: Fixed from version 6.0" }, ... ``` Add a second option "--output-inc-file" to also create a .inc at a given location. Both "--output-inc-file" and "--output-json-file" can be used at the same time. This commit doesn't affect or modify any existing behaviour of the script. Signed-off-by: Valentin Boudevin <valentin.boudevin@gmail.com> --- .../linux/generate-cve-exclusions.py | 107 +++++++++++++++--- 1 file changed, 90 insertions(+), 17 deletions(-)