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 <[email protected]> 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 <[email protected]>
> > Signed-off-by: Shunsuke Tokumoto <[email protected]>
> > ---
> >
> > 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 (#189672): 
https://lists.openembedded.org/g/openembedded-core/message/189672
Mute This Topic: https://lists.openembedded.org/mt/102172913/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to