Hi Marta,
I have some comments also to this respin.
Peter
> -----Original Message-----
> From: [email protected] <openembedded-
> [email protected]> On Behalf Of Marta Rybczynska via
> lists.openembedded.org
> Sent: Monday, August 12, 2024 6:09
> To: [email protected]
> Cc: Marta Rybczynska <[email protected]>
> Subject: [OE-core] [PATCH v4][OE-core 1/6] cve-check: encode affected
> product/vendor in CVE_STATUS
>
> CVE_STATUS contains assesment of a given CVE, but until now it didn't have
> include the affected vendor/product. In the case of a global system include,
> that CVE_STATUS was visible in all recipes.
>
> This patch allows encoding of affected product/vendor to each CVE_STATUS
> assessment, also for groups. We can then filter them later and use only
> CVEs that correspond to the recipe.
>
> This is going to be used in meta/conf/distro/include/cve-extra-exclusions.inc
> and similar places.
>
> Signed-off-by: Marta Rybczynska <[email protected]>
> ---
> meta/classes/cve-check.bbclass | 24 ++++++++++++------------
> meta/lib/oe/cve_check.py | 34 ++++++++++++++++++++++++----------
> meta/lib/oe/spdx30_tasks.py | 11 ++++++-----
> 3 files changed, 42 insertions(+), 27 deletions(-)
>
> diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
> index c946de29a4..bc35a1c53c 100644
> --- a/meta/classes/cve-check.bbclass
> +++ b/meta/classes/cve-check.bbclass
> @@ -324,8 +324,8 @@ def check_cves(d, patched_cves):
> # Convert CVE_STATUS into ignored CVEs and check validity
> cve_ignore = []
> for cve in (d.getVarFlags("CVE_STATUS") or {}):
> - decoded_status, _, _ = decode_cve_status(d, cve)
> - if decoded_status == "Ignored":
> + decoded_status = decode_cve_status(d, cve)
> + if 'mapping' in decoded_status and decoded_status['mapping'] ==
> "Ignored":
> cve_ignore.append(cve)
>
> import sqlite3
> @@ -507,11 +507,11 @@ def cve_write_data_text(d, patched, unpatched,
> ignored, cve_data):
> write_string += "PACKAGE VERSION: %s%s\n" % (d.getVar("EXTENDPE"),
> d.getVar("PV"))
> write_string += "CVE: %s\n" % cve
> write_string += "CVE STATUS: %s\n" % status
> - _, detail, description = decode_cve_status(d, cve)
> - if detail:
> - write_string += "CVE DETAIL: %s\n" % detail
> - if description:
> - write_string += "CVE DESCRIPTION: %s\n" % description
> + status_details = decode_cve_status(d, cve)
> + if 'detail' in status_details:
> + write_string += "CVE DETAIL: %s\n" % status_details['detail']
> + if 'description' in status_details:
> + write_string += "CVE DESCRIPTION: %s\n" %
> status_details['description']
> write_string += "CVE SUMMARY: %s\n" % cve_data[cve]["summary"]
> write_string += "CVSS v2 BASE SCORE: %s\n" % cve_data[cve]["scorev2"]
> write_string += "CVSS v3 BASE SCORE: %s\n" % cve_data[cve]["scorev3"]
> @@ -637,11 +637,11 @@ def cve_write_data_json(d, patched, unpatched,
> ignored, cve_data, cve_status):
> "status" : status,
> "link": issue_link
> }
> - _, detail, description = decode_cve_status(d, cve)
> - if detail:
> - cve_item["detail"] = detail
> - if description:
> - cve_item["description"] = description
> + status_details = decode_cve_status(d, cve)
> + if 'detail' in status_details:
> + cve_item["detail"] = status_details['detail']
> + if 'description' in status_details:
> + cve_item["description"] = status_details['description']
> cve_list.append(cve_item)
>
> package_data["issue"] = cve_list
> diff --git a/meta/lib/oe/cve_check.py b/meta/lib/oe/cve_check.py
> index ed5c714cb8..26dfdc1a54 100644
> --- a/meta/lib/oe/cve_check.py
> +++ b/meta/lib/oe/cve_check.py
> @@ -132,8 +132,8 @@ def get_patched_cves(d):
>
> # Search for additional patched CVEs
> for cve in (d.getVarFlags("CVE_STATUS") or {}):
> - decoded_status, _, _ = decode_cve_status(d, cve)
> - if decoded_status == "Patched":
> + decoded_status = decode_cve_status(d, cve)
> + if 'mapping' in decoded_status and decoded_status['mapping'] ==
> "Patched":
> bb.debug(2, "CVE %s is additionally patched" % cve)
> patched_cves.add(cve)
>
> @@ -227,19 +227,33 @@ def convert_cve_version(version):
>
> def decode_cve_status(d, cve):
> """
> - Convert CVE_STATUS into status, detail and description.
> + Convert CVE_STATUS into status, vendor, product, detail and description.
> """
> status = d.getVarFlag("CVE_STATUS", cve)
> if not status:
> - return ("", "", "")
> -
> - status_split = status.split(':', 1)
> - detail = status_split[0]
> - description = status_split[1].strip() if (len(status_split) > 1) else ""
> + return {}
> +
> + status_split = status.split(':', 5)
> + status_out = {}
> + status_out['detail'] = status_split[0]
> + if len(status_split) >= 4 and status_split[1].strip().startswith('cpe'):
Better is to do exact comparison with '=="cpe"', otherwise you still decide
wrong in case of:
ignore: cpe is wrong: other text: more text: even more text
> + # Both vendor and product are mandatory if cpe: present, the syntax
> is
> then:
> + # detail: cpe:vendor:product:description
> + status_out['vendor'] = status_split[2].strip() if (len(status_split)
> > 3) else
> "*"
> + status_out['product'] = status_split[3].strip() if
> (len(status_split) > 2) else
> "*"
The two clauses about have checks for len which always evaluates to true
because here the lengths is already >=4.
So please drop it, just do single assignment
> + elif len(status_split) >= 2 and
> status_split[1].strip().startswith('cpe'):
Same exact comparison as above should be also here, if we want to keep this
warning.
> + bb.warn('Invalid CPE information for CVE_STATUS[%s] = "%s", not
> setting
> CPE' % (detail, cve, status))
> + status_out['vendor'] = "*"
> + status_out['product'] = "*"
> + else:
> + status_out['vendor'] = "*"
> + status_out['product'] = "*"
> + status_out['description'] = status_split[len(status_split)-1].strip() if
> (len(status_split) > 1) else ""
The description can be crippled here in case of
ignore: cpe is wrong: other text: more text: even more text
(only "even more text" is chosen over the correct "cpe is wrong: other text:
more text: even more text")
So the status_out['description'] assignment should go to the if/else clauses
with hardcoded index of "4" of with new split to only two parts.
>
> - status_mapping = d.getVarFlag("CVE_CHECK_STATUSMAP", detail)
> + status_mapping = d.getVarFlag("CVE_CHECK_STATUSMAP",
> status_out['detail'])
> if status_mapping is None:
> bb.warn('Invalid detail "%s" for CVE_STATUS[%s] = "%s", fallback to
> Unpatched' % (detail, cve, status))
> status_mapping = "Unpatched"
> + status_out['mapping'] = status_mapping
>
> - return (status_mapping, detail, description)
> + return status_out
> diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py
> index 03dc47db02..4864d6252a 100644
> --- a/meta/lib/oe/spdx30_tasks.py
> +++ b/meta/lib/oe/spdx30_tasks.py
> @@ -488,21 +488,22 @@ def create_spdx(d):
> cve_by_status = {}
> if include_vex != "none":
> for cve in d.getVarFlags("CVE_STATUS") or {}:
> - status, detail, description = oe.cve_check.decode_cve_status(d,
> cve)
> + decoded_status = oe.cve_check.decode_cve_status(d, cve)
>
> # If this CVE is fixed upstream, skip it unless all CVEs are
> # specified.
> - if include_vex != "all" and detail in (
> + if include_vex != "all" and 'detail' in decoded_status and \
> + decoded_status['detail'] in (
> "fixed-version",
> "cpe-stable-backport",
> ):
> bb.debug(1, "Skipping %s since it is already fixed upstream"
> % cve)
> continue
>
> - cve_by_status.setdefault(status, {})[cve] = (
> + cve_by_status.setdefault(decoded_status['mapping'], {})[cve] = (
> build_objset.new_cve_vuln(cve),
> - detail,
> - description,
> + decoded_status['detail'],
> + decoded_status['description'],
> )
>
> cpe_ids = oe.cve_check.get_cpe_ids(d.getVar("CVE_PRODUCT"),
> d.getVar("CVE_VERSION"))
> --
> 2.43.0
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#203202):
https://lists.openembedded.org/g/openembedded-core/message/203202
Mute This Topic: https://lists.openembedded.org/mt/107851462/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-