Files
poky/meta/recipes-kernel/linux/generate-cve-exclusions.py
Ross Burton f17c07ff4b linux-yocto: add script to generate kernel CVE_CHECK_IGNORE entries
Instead of manually looking up new CVEs and determining what point
releases the fixes are incorporated into, add a script to generate the
CVE_CHECK_IGNORE data automatically.

First, note that this is very much an interim solution until the
cve-check class fetches data from www.linuxkernelcves.com directly.

The script should be passed the path to a local clone of the
linuxkernelcves repository[1] and the kernel version number. It will
then write to standard output the CVE_STATUS entries for every known
kernel CVE.

The script should be periodically reran as CVEs are backported and
kernels upgraded frequently.

[1] https://github.com/nluedtke/linux_kernel_cves

Note: for the backport this is not a cherry-pick of the commit in master
as the variable names are different. This incorporates the following
commits:

linux/generate-cve-exclusions: add version check warning
linux/generate-cve-exclusions.py: fix comparison
linux-yocto: add script to generate kernel CVE_STATUS entries

(From OE-Core rev: c7a71692b7ed4cc2187f4c82bf11e32e0ce32cb6)

Signed-off-by: Ross Burton <ross.burton@arm.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
2023-08-30 04:46:36 -10:00

102 lines
3.5 KiB
Python
Executable File

#! /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()} 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, last_affected = re.search(r"(.+) to (.+)", affected).groups()
first_affected = parse_version(first_affected)
last_affected = parse_version(last_affected)
handled = False
if not last_affected:
print(f"# {cve} has no known resolution")
elif first_affected and version < first_affected:
print(f"# fixed-version: only affects {first_affected} onwards")
handled = True
elif last_affected < version:
print(f"# fixed-version: Fixed after version {last_affected}")
handled = True
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"# cpe-stable-backport: Backported in {backport_ver}")
handled = True
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 {last_affected})")
else:
print(f"# {cve} needs backporting (fixed from {last_affected})")
if handled:
print(f'CVE_CHECK_IGNORE += "{cve}"')
print()
if __name__ == "__main__":
main()