diff options
| author | Marta Rybczynska <rybczynska@gmail.com> | 2024-08-14 07:30:37 +0200 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-08-20 14:12:40 +0100 |
| commit | fb3f440b7d808d4e29b6ab90e75313d5cf516c36 (patch) | |
| tree | d11a4884bc55f516c2e2dc2c139998b5cdd039a7 /meta/lib | |
| parent | ebc872441686e09708a23b0ee1d6d865481fbc09 (diff) | |
| download | poky-fb3f440b7d808d4e29b6ab90e75313d5cf516c36.tar.gz | |
cve-check: annotate CVEs during analysis
Add status information for each CVE under analysis.
Previously the information passed between different function of the
cve-check class included only tables of patched, unpatched, ignored
vulnerabilities and the general status of the recipe.
The VEX work requires more information, and we need to pass them
between different functions, so that it can be enriched as the
analysis progresses. Instead of multiple tables, use a single one
with annotations for each CVE encountered. For example, a patched
CVE will have:
{"abbrev-status": "Patched", "status": "version-not-in-range"}
abbrev-status contains the general status (Patched, Unpatched,
Ignored and Unknown that will be added in the VEX code)
status contains more detailed information that can come from
CVE_STATUS and the analysis.
Additional fields of the annotation include for example the name
of the patch file fixing a given CVE.
We also use the annotation in CVE_STATUS to filter out entries
that do not apply to the given recipe
(From OE-Core rev: 452e605b55ad61c08f4af7089a5a9c576ca28f7d)
Signed-off-by: Marta Rybczynska <marta.rybczynska@syslinbit.com>
Signed-off-by: Samantha Jalabert <samantha.jalabert@syslinbit.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib')
| -rw-r--r-- | meta/lib/oe/cve_check.py | 35 |
1 files changed, 29 insertions, 6 deletions
diff --git a/meta/lib/oe/cve_check.py b/meta/lib/oe/cve_check.py index 5edd34a2d9..487f30dc25 100644 --- a/meta/lib/oe/cve_check.py +++ b/meta/lib/oe/cve_check.py | |||
| @@ -88,7 +88,7 @@ def get_patched_cves(d): | |||
| 88 | # (cve_match regular expression) | 88 | # (cve_match regular expression) |
| 89 | cve_file_name_match = re.compile(r".*(CVE-\d{4}-\d+)", re.IGNORECASE) | 89 | cve_file_name_match = re.compile(r".*(CVE-\d{4}-\d+)", re.IGNORECASE) |
| 90 | 90 | ||
| 91 | patched_cves = set() | 91 | patched_cves = {} |
| 92 | patches = oe.patch.src_patches(d) | 92 | patches = oe.patch.src_patches(d) |
| 93 | bb.debug(2, "Scanning %d patches for CVEs" % len(patches)) | 93 | bb.debug(2, "Scanning %d patches for CVEs" % len(patches)) |
| 94 | for url in patches: | 94 | for url in patches: |
| @@ -98,7 +98,7 @@ def get_patched_cves(d): | |||
| 98 | fname_match = cve_file_name_match.search(patch_file) | 98 | fname_match = cve_file_name_match.search(patch_file) |
| 99 | if fname_match: | 99 | if fname_match: |
| 100 | cve = fname_match.group(1).upper() | 100 | cve = fname_match.group(1).upper() |
| 101 | patched_cves.add(cve) | 101 | patched_cves[cve] = {"abbrev-status": "Patched", "status": "fix-file-included", "resource": patch_file} |
| 102 | bb.debug(2, "Found %s from patch file name %s" % (cve, patch_file)) | 102 | bb.debug(2, "Found %s from patch file name %s" % (cve, patch_file)) |
| 103 | 103 | ||
| 104 | # Remote patches won't be present and compressed patches won't be | 104 | # Remote patches won't be present and compressed patches won't be |
| @@ -124,7 +124,7 @@ def get_patched_cves(d): | |||
| 124 | cves = patch_text[match.start()+5:match.end()] | 124 | cves = patch_text[match.start()+5:match.end()] |
| 125 | for cve in cves.split(): | 125 | for cve in cves.split(): |
| 126 | bb.debug(2, "Patch %s solves %s" % (patch_file, cve)) | 126 | bb.debug(2, "Patch %s solves %s" % (patch_file, cve)) |
| 127 | patched_cves.add(cve) | 127 | patched_cves[cve] = {"abbrev-status": "Patched", "status": "fix-file-included", "resource": patch_file} |
| 128 | text_match = True | 128 | text_match = True |
| 129 | 129 | ||
| 130 | if not fname_match and not text_match: | 130 | if not fname_match and not text_match: |
| @@ -133,9 +133,15 @@ def get_patched_cves(d): | |||
| 133 | # Search for additional patched CVEs | 133 | # Search for additional patched CVEs |
| 134 | for cve in (d.getVarFlags("CVE_STATUS") or {}): | 134 | for cve in (d.getVarFlags("CVE_STATUS") or {}): |
| 135 | decoded_status = decode_cve_status(d, cve) | 135 | decoded_status = decode_cve_status(d, cve) |
| 136 | if 'mapping' in decoded_status and decoded_status['mapping'] == "Patched": | 136 | products = d.getVar("CVE_PRODUCT") |
| 137 | bb.debug(2, "CVE %s is additionally patched" % cve) | 137 | if has_cve_product_match(decoded_status, products) == True: |
| 138 | patched_cves.add(cve) | 138 | patched_cves[cve] = { |
| 139 | "abbrev-status": decoded_status["mapping"], | ||
| 140 | "status": decoded_status["detail"], | ||
| 141 | "justification": decoded_status["description"], | ||
| 142 | "affected-vendor": decoded_status["vendor"], | ||
| 143 | "affected-product": decoded_status["product"] | ||
| 144 | } | ||
| 139 | 145 | ||
| 140 | return patched_cves | 146 | return patched_cves |
| 141 | 147 | ||
| @@ -264,3 +270,20 @@ def decode_cve_status(d, cve): | |||
| 264 | status_out["mapping"] = status_mapping | 270 | status_out["mapping"] = status_mapping |
| 265 | 271 | ||
| 266 | return status_out | 272 | return status_out |
| 273 | |||
| 274 | def has_cve_product_match(detailed_status, products): | ||
| 275 | """ | ||
| 276 | Check product/vendor match between detailed_status from decode_cve_status and a string of | ||
| 277 | products (like from CVE_PRODUCT) | ||
| 278 | """ | ||
| 279 | for product in products.split(): | ||
| 280 | vendor = "*" | ||
| 281 | if ":" in product: | ||
| 282 | vendor, product = product.split(":", 1) | ||
| 283 | |||
| 284 | if (vendor == detailed_status["vendor"] or detailed_status["vendor"] == "*") and \ | ||
| 285 | (product == detailed_status["product"] or detailed_status["product"] == "*"): | ||
| 286 | return True | ||
| 287 | |||
| 288 | #if no match, return False | ||
| 289 | return False | ||
