Hello Marta,

Major reason why we introduced CVE_STATUS was exactly to avoid patch like this.
There were ideas to introduce 5 or 10 or 15 different statuses and we decided 
to keep 3 and introduce “sub-statuses”.
These sub-statuses are listed in cve reports, too.

Currently we have three main statuses:
Patched – common status for all sub-statuses which indicate that component is 
not vulnerable
Unpatched - common status for all sub-statuses which indicate that component is 
vulnerable
Ignored - common status for all sub-statuses which indicate that component is 
vulnerable but not in yocto configuration context

If we don’t like “Patched” we can rename it (e.g. to  “Unaffected”) and have 
additional sub-statuses under this new name.
Otherwise we start exploding the statuses as someone will “need” additional one 
soon.

If we really want to introduce these new statues (I hope not), please modify 
this patch to handle its CVE_STATUS flags, too.
Additionally, I’d drop “Undecidable” and map it to “Unpatched” (so someone 
needs to analyze as any other open vulnerability report)

Best Regards,
  Peter

From: Marta Rybczynska <rybczyn...@gmail.com>
Sent: Wednesday, October 25, 2023 14:44
To: Andrej Valek <andre...@skyrain.eu>
Cc: Matsunaga-Shinji <shin.matsun...@fujitsu.com>; Richard Purdie 
<richard.pur...@linuxfoundation.org>; OE-core 
<openembedded-core@lists.openembedded.org>; Shunsuke Tokumoto 
<s-tokum...@fujitsu.com>; Marko, Peter (ADV D EU SK BFS1) 
<peter.ma...@siemens.com>
Subject: Re: [OE-core] [PATCH v2] cve-check: Classify patched CVEs into 3 
statuses

Hello Andrej,
This patch is splitting the Patched state, not the ignore one. This is not 
incorrect CPE or anything else.

Currently Patched means one of two situations: either this issue has never 
affected the code base (example: we have version 1.0, issue was introduced in 
2.0 and fixed in 2.1), or the issue has been fixed.

Yes, another reason to say ignore, not affected is a manual analysis showing a 
thing like: the issue affects only windows.

Regards,
Marta

On Wed, 25 Oct 2023, 12:18 Andrej Valek, 
<andre...@skyrain.eu<mailto:andre...@skyrain.eu>> wrote:
Hi Marta,

That's fine, as I said we designed the "ignore" with status
"cpe-incorrect" or "ignored" exactly for those purposes. Extending the
option with "not affected" doesn't make any sense.

You have to set the status to "why is not affected" = "ignored". Which
completely covers the requested case.

Regards,
Andrej

On 25.10.2023 11:33, Marta Rybczynska wrote:
> Hi Andrej,
> This is more complex. "Not affected" is also an issue that isn't present in 
> the
> code - like when we have a version that has never had the vulnerability.
> Those are also currently 'Patched' in cve-check.
>
> This work is in sync with what VEX is doing, is it the use-case
> Matsanaga-Shinji?
>
> Regards,
> Marta
>
> On Wed, Oct 25, 2023 at 8:44 AM Andrej Valek 
> <andre...@skyrain.eu<mailto:andre...@skyrain.eu>> wrote:
>> Hi all,
>>
>> Do we really need a new "not_affected" state? I guess the ignore state
>> is exactly designed for those purposes.
>>
>> Regards,
>> Andrej
>>
>> On 25.10.2023 07:13, Matsunaga-Shinji wrote:
>>> CVEs that are currently considered "Patched" are classified into the 
>>> following 3 statuses:
>>> 1. "Patched"      - means that a patch file that fixed the vulnerability 
>>> has been applied
>>> 2. "Not affected" - means that the package version (PV) is not affected by 
>>> the vulnerability
>>> 3. "Undecidable"  - means that versions cannot be compared to determine if 
>>> they are affected by the vulnerability
>>>
>>> Signed-off-by: Shinji Matsunaga 
>>> <shin.matsun...@fujitsu.com<mailto:shin.matsun...@fujitsu.com>>
>>> Signed-off-by: Shunsuke Tokumoto 
>>> <s-tokum...@fujitsu.com<mailto:s-tokum...@fujitsu.com>>
>>> ---
>>>
>>> Changes for v2:
>>>      - Fix the status "Out of range" to "Not affected"
>>>
>>>    meta/classes/cve-check.bbclass | 55 +++++++++++++++++++++++-----------
>>>    1 file changed, 38 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
>>> index b55f4299da..502db324df 100644
>>> --- a/meta/classes/cve-check.bbclass
>>> +++ b/meta/classes/cve-check.bbclass
>>> @@ -185,10 +185,10 @@ python do_cve_check () {
>>>                    patched_cves = get_patched_cves(d)
>>>                except FileNotFoundError:
>>>                    bb.fatal("Failure in searching patches")
>>> -            ignored, patched, unpatched, status = check_cves(d, 
>>> patched_cves)
>>> -            if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == 
>>> "1" and status):
>>> -                cve_data = get_cve_info(d, patched + unpatched + ignored)
>>> -                cve_write_data(d, patched, unpatched, ignored, cve_data, 
>>> status)
>>> +            ignored, patched, unpatched, not_affected, undecidable, status 
>>> = check_cves(d, patched_cves)
>>> +            if patched or unpatched or not_affected or undecidable or 
>>> (d.getVar("CVE_CHECK_COVERAGE") == "1" and status):
>>> +                cve_data = get_cve_info(d, patched + unpatched + ignored + 
>>> not_affected + undecidable)
>>> +                cve_write_data(d, patched, unpatched, ignored, 
>>> not_affected, undecidable, cve_data, status)
>>>            else:
>>>                bb.note("No CVE database found, skipping CVE check")
>>>
>>> @@ -308,13 +308,13 @@ def check_cves(d, patched_cves):
>>>        products = d.getVar("CVE_PRODUCT").split()
>>>        # If this has been unset then we're not scanning for CVEs here (for 
>>> example, image recipes)
>>>        if not products:
>>> -        return ([], [], [], [])
>>> +        return ([], [], [], [], [], [])
>>>        pv = d.getVar("CVE_VERSION").split("+git")[0]
>>>
>>>        # If the recipe has been skipped/ignored we return empty lists
>>>        if pn in d.getVar("CVE_CHECK_SKIP_RECIPE").split():
>>>            bb.note("Recipe has been skipped by cve-check")
>>> -        return ([], [], [], [])
>>> +        return ([], [], [], [], [], [])
>>>
>>>        # Convert CVE_STATUS into ignored CVEs and check validity
>>>        cve_ignore = []
>>> @@ -328,6 +328,8 @@ def check_cves(d, patched_cves):
>>>        conn = sqlite3.connect(db_file, uri=True)
>>>
>>>        # For each of the known product names (e.g. curl has CPEs using curl 
>>> and libcurl)...
>>> +    cves_not_affected = []
>>> +    cves_undecidable = []
>>>        for product in products:
>>>            cves_in_product = False
>>>            if ":" in product:
>>> @@ -355,6 +357,7 @@ def check_cves(d, patched_cves):
>>>
>>>                vulnerable = False
>>>                ignored = False
>>> +            undecidable = False
>>>
>>>                product_cursor = conn.execute("SELECT * FROM PRODUCTS WHERE 
>>> ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor))
>>>                for row in product_cursor:
>>> @@ -376,7 +379,7 @@ def check_cves(d, patched_cves):
>>>                            except:
>>>                                bb.warn("%s: Failed to compare %s %s %s for 
>>> %s" %
>>>                                        (product, pv, operator_start, 
>>> version_start, cve))
>>> -                            vulnerable_start = False
>>> +                            undecidable = True
>>>                        else:
>>>                            vulnerable_start = False
>>>
>>> @@ -387,10 +390,15 @@ def check_cves(d, patched_cves):
>>>                            except:
>>>                                bb.warn("%s: Failed to compare %s %s %s for 
>>> %s" %
>>>                                        (product, pv, operator_end, 
>>> version_end, cve))
>>> -                            vulnerable_end = False
>>> +                            undecidable = True
>>>                        else:
>>>                            vulnerable_end = False
>>>
>>> +                    if undecidable:
>>> +                        bb.note("%s-%s is undecidable to %s" % (pn, 
>>> real_pv, cve))
>>> +                        cves_undecidable.append(cve)
>>> +                        break
>>> +
>>>                        if operator_start and operator_end:
>>>                            vulnerable = vulnerable_start and vulnerable_end
>>>                        else:
>>> @@ -406,9 +414,9 @@ def check_cves(d, patched_cves):
>>>                        break
>>>                product_cursor.close()
>>>
>>> -            if not vulnerable:
>>> +            if not undecidable and not vulnerable:
>>>                    bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, 
>>> cve))
>>> -                patched_cves.add(cve)
>>> +                cves_not_affected.append(cve)
>>>            cve_cursor.close()
>>>
>>>            if not cves_in_product:
>>> @@ -420,7 +428,7 @@ def check_cves(d, patched_cves):
>>>        if not cves_in_recipe:
>>>            bb.note("No CVE records for products in recipe %s" % (pn))
>>>
>>> -    return (list(cves_ignored), list(patched_cves), cves_unpatched, 
>>> cves_status)
>>> +    return (list(cves_ignored), list(patched_cves), cves_unpatched, 
>>> cves_not_affected, cves_undecidable, cves_status)
>>>
>>>    def get_cve_info(d, cves):
>>>        """
>>> @@ -447,7 +455,7 @@ def get_cve_info(d, cves):
>>>        conn.close()
>>>        return cve_data
>>>
>>> -def cve_write_data_text(d, patched, unpatched, ignored, cve_data):
>>> +def cve_write_data_text(d, patched, unpatched, ignored, not_affected, 
>>> undecidable, cve_data):
>>>        """
>>>        Write CVE information in WORKDIR; and to CVE_CHECK_DIR, and
>>>        CVE manifest if enabled.
>>> @@ -471,7 +479,7 @@ def cve_write_data_text(d, patched, unpatched, ignored, 
>>> cve_data):
>>>            return
>>>
>>>        # Early exit, the text format does not report packages without CVEs
>>> -    if not patched+unpatched+ignored:
>>> +    if not patched+unpatched+ignored+not_affected+undecidable:
>>>            return
>>>
>>>        nvd_link = "https://nvd.nist.gov/vuln/detail/";
>>> @@ -482,6 +490,8 @@ def cve_write_data_text(d, patched, unpatched, ignored, 
>>> cve_data):
>>>        for cve in sorted(cve_data):
>>>            is_patched = cve in patched
>>>            is_ignored = cve in ignored
>>> +        is_not_affected = cve in not_affected
>>> +        is_undecidable = cve in undecidable
>>>
>>>            status = "Unpatched"
>>>            if (is_patched or is_ignored) and not report_all:
>>> @@ -490,6 +500,10 @@ def cve_write_data_text(d, patched, unpatched, 
>>> ignored, cve_data):
>>>                status = "Ignored"
>>>            elif is_patched:
>>>                status = "Patched"
>>> +        elif is_not_affected:
>>> +            status = "Not affected"
>>> +        elif is_undecidable:
>>> +            status = "Undecidable"
>>>            else:
>>>                # default value of status is Unpatched
>>>                unpatched_cves.append(cve)
>>> @@ -561,7 +575,7 @@ def cve_check_write_json_output(d, output, direct_file, 
>>> deploy_file, manifest_fi
>>>            with open(index_path, "a+") as f:
>>>                f.write("%s\n" % fragment_path)
>>>
>>> -def cve_write_data_json(d, patched, unpatched, ignored, cve_data, 
>>> cve_status):
>>> +def cve_write_data_json(d, patched, unpatched, ignored, not_affected, 
>>> undecidable, cve_data, cve_status):
>>>        """
>>>        Prepare CVE data for the JSON format, then write it.
>>>        """
>>> @@ -606,6 +620,9 @@ def cve_write_data_json(d, patched, unpatched, ignored, 
>>> cve_data, cve_status):
>>>        for cve in sorted(cve_data):
>>>            is_patched = cve in patched
>>>            is_ignored = cve in ignored
>>> +        is_not_affected = cve in not_affected
>>> +        is_undecidable = cve in undecidable
>>> +
>>>            status = "Unpatched"
>>>            if (is_patched or is_ignored) and not report_all:
>>>                continue
>>> @@ -613,6 +630,10 @@ def cve_write_data_json(d, patched, unpatched, 
>>> ignored, cve_data, cve_status):
>>>                status = "Ignored"
>>>            elif is_patched:
>>>                status = "Patched"
>>> +        elif is_not_affected:
>>> +            status = "Not affected"
>>> +        elif is_undecidable:
>>> +            status = "Undecidable"
>>>            else:
>>>                # default value of status is Unpatched
>>>                unpatched_cves.append(cve)
>>> @@ -645,12 +666,12 @@ def cve_write_data_json(d, patched, unpatched, 
>>> ignored, cve_data, cve_status):
>>>
>>>        cve_check_write_json_output(d, output, direct_file, deploy_file, 
>>> manifest_file)
>>>
>>> -def cve_write_data(d, patched, unpatched, ignored, cve_data, status):
>>> +def cve_write_data(d, patched, unpatched, ignored, not_affected, 
>>> undecidable, cve_data, status):
>>>        """
>>>        Write CVE data in each enabled format.
>>>        """
>>>
>>>        if d.getVar("CVE_CHECK_FORMAT_TEXT") == "1":
>>> -        cve_write_data_text(d, patched, unpatched, ignored, cve_data)
>>> +        cve_write_data_text(d, patched, unpatched, ignored, not_affected, 
>>> undecidable, cve_data)
>>>        if d.getVar("CVE_CHECK_FORMAT_JSON") == "1":
>>> -        cve_write_data_json(d, patched, unpatched, ignored, cve_data, 
>>> status)
>>> +        cve_write_data_json(d, patched, unpatched, ignored, not_affected, 
>>> undecidable, cve_data, status)
>>>
>>> 
>>>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#189677): 
https://lists.openembedded.org/g/openembedded-core/message/189677
Mute This Topic: https://lists.openembedded.org/mt/102172913/21656
Group Owner: openembedded-core+ow...@lists.openembedded.org
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to