Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alpine secdb should only be used to remove matches, never to add matches #970

Open
luhring opened this issue Oct 28, 2022 · 11 comments · May be fixed by #1318
Open

Alpine secdb should only be used to remove matches, never to add matches #970

luhring opened this issue Oct 28, 2022 · 11 comments · May be fixed by #1318
Assignees
Labels
bug Something isn't working

Comments

@luhring
Copy link
Contributor

luhring commented Oct 28, 2022

While looking into #964, @spiffcs discovered that when Grype started using Alpine's secdb data for edge, Grype began surfacing additional vulnerability matches that hadn't shown up before.

This indicates an incorrect behavior for Grype's existing Alpine matching: Alpine secfixes denote only fixes to packages — never vulnerabilities themselves. The secdb should only ever be used to remove existing matches (i.e. from NVD data) from the final result set.

Here are some examples of correct behavior for illustration:

Match in NVD only

Packages:

  • zlib at v1.2.3-r1

NVD:

  • CVE X — affected versions: < v1.4.2

Expected result:

  • zlib — v1.2.3-r1 — CVE X

Match in NVD and Alpine secdb

Packages:

  • zlib at v1.2.3-r2

NVD:

  • CVE X — affected versions: < v1.4.2

Secdb:

  • zlib: v1.2.3-r2 fixes CVE X

Expected result:

  • (nothing)

Match in Alpine secdb only

Packages:

  • zlib at v1.2.3-r0

Secdb:

  • zlib: v1.3.3-r0 fixes CVE X

Expected result:

  • (nothing)
@luhring luhring added the bug Something isn't working label Oct 28, 2022
@spiffcs spiffcs self-assigned this Nov 3, 2022
@kzantow
Copy link
Contributor

kzantow commented May 25, 2023

Developer notes:

On the surface, it looks like we could rewrite the findApkPackage from here to remove the secdb stuff, e.g.:

func (m *Matcher) findApkPackage(store vulnerability.Provider, d *distro.Distro, p pkg.Package) ([]match.Match, error) {
	return m.cpeMatchesWithoutSecDBFixes(store, d, p)
}

@wagoodman
Copy link
Contributor

@westonsteimel and I were discussing this a little further this morning, and I'm starting to think that both approaches are valid depending on the users risk tolerance. That is, the proposed change to not use the secdb to add matches to the results is textbook-wise correct, however, matching against NVD is notoriously error prone too... which may lead to higher FNs, which may be more sensitive over the raised FPs from this approach.

I'm starting to think that the matcher should allow for either strategy:

  • matching strategy 1: use (NVD - secDB fixes) + remaining secDB results
  • matching strategy 2: use (NVD - secDB fixes) results

This could be controlled with a new match.alpine.include-secdb-matches app configurable.

Additionally we could augment the output to show in the table view which matches came directly from secDB and annotate a hint on a lower confidence about those results. (maybe even add a match.alpine.warn-on-secdb-matches configuration option for this)

I think this biggest question about this approach is what should be the default posture? I'm leaning towards the second matching strategy (what's originally being proposed), but I have a couple of questions:

  1. Do we know how many matches this affects on various alpine/wolfi images? We can't know the full universe of possible matches here, but I'm curious for a given image that shows this behavior, does it affect a few results, most of the results, etc?
  2. Is this more likely to affect distros that are using the "edge" publishing approach?

One more note for anyone picking this up (CC @spiffcs ): we have a lot of labels already for alpine that will probably need to be redone.

@luhring
Copy link
Contributor Author

luhring commented May 26, 2023

Hey! Here's how I would suggest thinking about this:

First, I think "what's best today" might differ from "what's best down the road". Especially for the Wolfi part of your questioning, I can say authoritatively that our approach to providing security data is going to diverge from Alpine's, and in the not-too-distant future. In fact, just yesterday we cutover our secdb from being produced from "secfixes" to the newer "advisory data".

As we've discussed, I believe that with the Wolfi security data evolution will come more reasons to trust the data as a (potentially sole) means of detecting vulnerabilities within Wolfi packages. The recommendation for how to use Wolfi data in the future (which would include using as a first-class means of discovering vulns) would be significantly different from the recommendation on how to use the Alpine-style secdb, which is purely subtractive according to the Alpine security team.

For today, I'd advise following the Alpine team's guidance for Alpine, and for Wolfi/Chainguard matching as well. This means "strategy 2", which the distros involved here agree is the correct behavior.

@spiffcs can correct me if I'm wrong about the following — but IIRC, when we discovered the unexpected matches from the additive approach, the findings were all FPs. That makes intuitive sense to me. I get the motivation of defending against FNs at all costs, but it might actually be a phantom problem here. If you're seeing evidence of FNs in Alpine resulting from "strategy 2", it'd be good to explore those here. But until then, it could be that the only difference between the correct matching approach and the modified matching approach is an addition of FPs. (But of course the data would show if FNs are a concern here.)

@willmurphyscode
Copy link
Contributor

@luhring I'm looking at picking up this work, but it's been a while. Is your previous comment still correct and this work still needed? Would you mind taking a look at @spiffcs 's questions on #1318? Happy to set up a time to chat about this as well.

@luhring
Copy link
Contributor Author

luhring commented Oct 2, 2023

Hey @willmurphyscode! I think my previous comment is still correct. And I just replied on #1318.

Also happy to set up a time to chat, on this and other related enhancements. Would love to meet you! Feel free to DM me on the Anchore community Slack or something. 😃

@wagoodman
Copy link
Contributor

I want to re-raise this:

the proposed change to not use the secdb to add matches to the results is textbook-wise correct, however, matching against NVD is notoriously error prone too... which may lead to higher FNs, which may be more sensitive over the raised FPs from this approach.

Let me take an example from the PR: GHSA-vpvm-3wq2-2wvm (CVE-2023-27561 against runc).

The NVD data has the following information (as of today):

  • match based on cpe:2.3:a:linuxfoundation:runc:*:*:*:*:*:*:*:*
  • consider < 1.1.5 as vulnerable
(vunnel output of NVD results from today, Cct 28 2023)
{
  "schema": "https://raw.githubusercontent.com/anchore/vunnel/main/schema/vulnerability/nvd/schema-1.0.0.json",
  "identifier": "2023/cve-2023-27561",
  "item": {
    "cve": {
      "id": "CVE-2023-27561",
      "sourceIdentifier": "cve@mitre.org",
      "published": "2023-03-03T19:15:11.330",
      "lastModified": "2023-08-16T03:15:26.440",
      "vulnStatus": "Modified",
      "descriptions": [
        {
          "lang": "en",
          "value": "runc through 1.1.4 has Incorrect Access Control leading to Escalation of Privileges, related to libcontainer/rootfs_linux.go. To exploit this, an attacker must be able to spawn two containers with custom volume-mount configurations, and be able to run custom images. NOTE: this issue exists because of a CVE-2019-19921 regression."
        }
      ],
      "metrics": {
        "cvssMetricV31": [
          {
            ... snip ...
          }
        ]
      },
      "weaknesses": [
        {
          "source": "nvd@nist.gov",
          "type": "Primary",
          "description": [
            {
              "lang": "en",
              "value": "CWE-706"
            }
          ]
        }
      ],
      "configurations": [
        {
          "nodes": [
            {
              "operator": "OR",
              "negate": false,
              "cpeMatch": [
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:a:linuxfoundation:runc:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "1.1.5",
                  "matchCriteriaId": "AE0C5D34-F78A-4993-AC70-25A6606FC82B"
                }
              ]
            }
          ]
        },
        {
          "nodes": [
            {
              "operator": "OR",
              "negate": false,
              "cpeMatch": [
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:a:redhat:openshift_container_platform:4.0:*:*:*:*:*:*:*",
                  "matchCriteriaId": "932D137F-528B-4526-9A89-CD59FA1AB0FE"
                },
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:o:redhat:enterprise_linux:8.0:*:*:*:*:*:*:*",
                  "matchCriteriaId": "F4CFF558-3C47-480D-A2F0-BABF26042943"
                },
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:o:redhat:enterprise_linux:9.0:*:*:*:*:*:*:*",
                  "matchCriteriaId": "7F6FB57C-2BC7-487C-96DD-132683AEB35D"
                }
              ]
            }
          ]
        },
        {
          "nodes": [
            {
              "operator": "OR",
              "negate": false,
              "cpeMatch": [
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:o:debian:debian_linux:10.0:*:*:*:*:*:*:*",
                  "matchCriteriaId": "07B237A9-69A3-4A9C-9DA0-4E06BD37AE73"
                }
              ]
            }
          ]
        }
      ],
      "references": [
        ... snip ...
      ]
    }
  }
}

Let's focus just on alpine:3.17. Based on the secdb entries for this CVE we know that there were multiple fixes introduced for this CVE:

  • 1.1.4-r6
  • 1.1.5-r0
(grype db entries for CVE-2023-27561 relating to alpine)
$ sqlite3 ./vulnerability.db 'SELECT *  FROM vulnerability where id == "CVE-2023-27561";'

230110|CVE-2023-27561|runc|nvd:cpe||< 1.1.5|unknown|["cpe:2.3:a:linuxfoundation:runc:*:*:*:*:*:*:*:*"]|||unknown|
...
276149|CVE-2023-27561|runc|alpine:distro:alpine:3.17||< 1.1.4-r6|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.4-r6"]|fixed|
276150|CVE-2023-27561|runc|alpine:distro:alpine:3.17||< 1.1.5-r0|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.5-r0"]|fixed|
282934|CVE-2023-27561|runc|alpine:distro:alpine:3.18||< 1.1.4-r0|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.4-r0"]|fixed|
282935|CVE-2023-27561|runc|alpine:distro:alpine:3.18||< 1.1.4-r7|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.4-r7"]|fixed|
298710|CVE-2023-27561|runc|alpine:distro:alpine:edge||< 1.1.4-r0|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.4-r0"]|fixed|
298711|CVE-2023-27561|runc|alpine:distro:alpine:edge||< 1.1.4-r7|apk||[{"id":"CVE-2023-27561","namespace":"nvd:cpe"}]|["1.1.4-r7"]|fixed|
...
(secfixes comments at v3.17.5)
# secfixes:
#   1.1.5-r0:
#     - CVE-2023-25809
#     - CVE-2023-27561
#     - CVE-2023-28642
#   1.1.4-r6:
#     - CVE-2023-27561
#   1.1.2-r0:
#     - CVE-2022-29162
#   1.0.3-r0:
#     - CVE-2021-43784
#   1.0.0_rc95-r0:
#     - CVE-2021-30465
#   1.0.0_rc10-r0:
#     - CVE-2019-19921
#   1.0.0_rc9-r0:
#     - CVE-2019-16884
#   1.0.0_rc7-r0:
#     - CVE-2019-5736

Still focusing on alpine:3.17 there are a few releases to keep in mind:

  • 3.17.0: runc at time of ship was 1.1.4-r3 and vulnerable
  • 3.17.1: runc at time of ship was 1.1.4-r4 and vulnerable
  • 3.17.2: runc at time of ship was 1.1.4-r4 and vulnerable
  • 3.17.3: runc at time of ship was 1.1.4-r6 and NOT vulnerable
  • 3.17.4: runc at time of ship was 1.1.5-r2 and NOT vulnerable
  • 3.17.5: runc at time of ship was 1.1.5-r2 and NOT vulnerable

If we use the NVD data (< 1.1.5 is vulnerable) then 3.17.x container images built with these runc versions then I'd expect today's matching approach and the proposed matching approach to both be correct.

Let's extend this example into a hypothetical: assume that the patch for 1.1.5-r3 mistakenly regresses the behavior of runc in such a way where we are vulnerable to the issue described in CVE-2023-27561. Let's also assume that this isn't caught for another few patches, say, until it is re-patched (re-fixed) in 1.1.5-r5. (<-- again, these set of versions are hypothetical, no links to show!)

That would mean that the "correct" vulnerable range of releases are: (>= 1.1.4, < 1.1.4-r6) || ( >= 1.1.5-r3, < 1.1.5-r5)
From a secdb point of view, this would result in two entries:

  • 1.1.4-r6
  • 1.1.5-r5

It's true, that we cannot infer the correct ranges from the secdb entries. What we'd do today is: < 1.1.4-r6 || < 1.1.5-r5 . I think this could be improved to (a still incorrect but better range): < 1.1.4-r6 || (> 1.1.5, < 1.1.5-r5) . We also cannot infer the correct ranges from NVD either. The best we'd be able to do is < 1.1.5 until NVD updated their data based on the versions from the upstream source repo and not alpine releases.

This is just one dimension of the problem. There is an equally important problem to consider: can we accurately craft an CPE for all APKs in the alpine ecosystem for matching against NVD? Assuming the vendor and product must match, I don't think this problem has been cracked yet.

Take for example the CVE-2023-27561 we've been talking through above:

  • Syft crafts a CPE of cpe:2.3:a:runc:runc:1.1.7-r4:*:*:*:*:*:*:*
  • The NVD record has cpe:2.3:a:linuxfoundation:runc:*:*:*:*:*:*:*:* (see the "vunnel output of NVD results" json detail above)
There is nothing in the APK record or binary to indicate that the linuxfoundation is a possible vendor.

Take the /lib/apk/db/installed snippet:

C:Q1pKfos0+G10KxhmSLsuyXDINZZF0=
P:runc
V:1.1.5-r2
A:aarch64
S:3321486
I:9379840
T:CLI tool for spawning and running containers according to the OCI specification
U:https://www.opencontainers.org
L:Apache-2.0
o:runc
m:Jake Buchholz Göktürk <tomalok@gmail.com>
t:1683096588
c:102db92046840ff2e74ee1d3b877c000a9b9232f
D:so:libc.musl-aarch64.so.1 so:libseccomp.so.2
p:cmd:runc=1.1.5-r2
F:usr
F:usr/bin
R:runc
a:0:0:755
Z:Q1tA+PBkwT5ifBnL5MQ+MLQwIZlKs=

The best candidate is the opencontainers reference, which is still incorrect.

The go module is github.com/opencontainers/runc and no hint of linuxfoundation in the go module information:

$ go version -m ./runc | grep linux
	dep	github.com/opencontainers/selinux	v1.10.0
	build	GOOS=linux

Nor even in the binary directly:

$ strings ./runc | grep linuxfoundation
$

We have a growing set of manually-crafted mappings for apk packages that need a better, more automated solution for figuring the correct vendor for a given package when generating a CPE.

@wagoodman
Copy link
Contributor

Let's look at another example, CVE-2019-9210 against advancecomp, it seems that there is not enough information to be able to make a CPE match based on vendor information not being available in the packaging or the artifact.

(syft json snippet)
{
...
  "cpes": [
    "cpe:2.3:a:advancecomp:advancecomp:2.5-r1:*:*:*:*:*:*:*"
  ],
  "purl": "pkg:apk/alpine/advancecomp@2.5-r1?arch=aarch64&distro=alpine-3.18.4",
  "metadataType": "ApkMetadata",
  "metadata": {
    "package": "advancecomp",
    "originPackage": "advancecomp",
    "maintainer": "TBK <alpine@jjtc.eu>",
    "version": "2.5-r1",
    "architecture": "aarch64",
    "url": "https://www.advancemame.it/",
    "description": "A collection of recompression utilities for your .ZIP archives, .PNG snapshots, .MNG video clips and .GZ files",
    "size": 471494,
    "installedSize": 1077248,
    "pullDependencies": [
      "so:libc.musl-aarch64.so.1",
      "so:libgcc_s.so.1",
      "so:libstdc++.so.6",
      "so:libz.so.1"
    ],
...
}

There is a chance of pulling it from the URL, but this is not a dependable method in many cases.

(grype-db entries for advancecomp)
152187|CVE-2019-9210|advancecomp|nvd:cpe||= 2.1|unknown|["cpe:2.3:a:advancemame:advancecomp:2.1:*:*:*:*:*:*:*"]|||unknown|
247400|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.12||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
251038|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.13||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
255167|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.14||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
260050|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.15||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
265615|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.16||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
271912|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.17||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
278541|CVE-2019-9210|advancecomp|alpine:distro:alpine:3.18||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|
294390|CVE-2019-9210|advancecomp|alpine:distro:alpine:edge||< 2.1-r2|apk||[{"id":"CVE-2019-9210","namespace":"nvd:cpe"}]|["2.1-r2"]|fixed|

In this case we would not be able to reliably match against NVD (given we cannot find the right vendor), so it would be a FN.

@wagoodman
Copy link
Contributor

Taking a look at CVE-2018-12126 for intel-ucode the NVD CPE is cpe:2.3:o:intel:microarchitectural_store_buffer_data_sampling_firmware:-:*:*:*:*:*:*:*. The product name is nowhere to be found in the APK packaging info (closest is Intel-Linux-Processor-Microcode-Data-Files which isn't very close). Taking a look at the type I'm only seeing h and o and not a) which means that there is no hope of connecting this with the alpine package. Grype would not be able to match against this package at all.

From a "which versions are patched vs not" point of view this is a great example; patched in:

  • 20191112-r0
  • 20190618-r0
  • 20190514a-r0
(secfix comments from main branch)
# (Taken from https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/blob/main/releasenote.md)
# secfixes:
#   20230808-r0:
#     - CVE-2022-40982
#     - CVE-2022-41804
#     - CVE-2023-23908
#   20230214-r0:
#     - CVE-2022-21216
#     - CVE-2022-33196
#     - CVE-2022-38090
#   20220809-r0:
#     - CVE-2022-21233
#   20220510-r0:
#     - CVE-2022-21151
#   20220207-r0:
#     - CVE-2021-0127
#     - CVE-2021-0146
#   20210608-r0:
#     - CVE-2020-24489
#     - CVE-2020-24511
#     - CVE-2020-24513
#   20210216-r0:
#     - CVE-2020-8698
#   20201112-r0:
#     - CVE-2020-8694
#     - CVE-2020-8698
#   20201110-r0:
#     - CVE-2020-8694
#     - CVE-2020-8698
#   20200609-r0:
#     - CVE-2020-0548
#   20191113-r0:
#     - CVE-2019-11135
#   20191112-r0:
#     - CVE-2018-12126         <--- here!
#     - CVE-2019-11135
#   20190918-r0:
#     - CVE-2019-11135
#   20190618-r0:
#     - CVE-2018-12126         <--- here!
#   20190514a-r0:
#     - CVE-2018-12126         <--- here!
#     - CVE-2017-5754
#     - CVE-2017-5753
(grype-db entries for alpine 3.12)
$ sqlite3 ./vulnerability.db 'SELECT *  FROM vulnerability where id == "CVE-2018-12126";' | grep 'alpine:3.12'

246117|CVE-2018-12126|intel-ucode|alpine:distro:alpine:3.12||< 20190514a-r0|apk||[{"id":"CVE-2018-12126","namespace":"nvd:cpe"}]|["20190514a-r0"]|fixed|
246118|CVE-2018-12126|intel-ucode|alpine:distro:alpine:3.12||< 20190618-r0|apk||[{"id":"CVE-2018-12126","namespace":"nvd:cpe"}]|["20190618-r0"]|fixed|
246119|CVE-2018-12126|intel-ucode|alpine:distro:alpine:3.12||< 20191112-r0|apk||[{"id":"CVE-2018-12126","namespace":"nvd:cpe"}]|["20191112-r0"]|fixed|

This one is interesting in the sense that we might be able to pick up that the version is date-ish, but we don't have that capability today. If we were able to pick up on that then we could put together a better range of < 20191112-r0, != 20190514a-r0, != 20190618-r0 (there might be other variants here, not diving too deep).

Say we were able to match against the NVD record via CPE, the version story isn't promising: all versions are vulnerable.

@wagoodman
Copy link
Contributor

Looking at CVE-2022-20612 against jenkins:

(secfixes comments on alpine)

From the APKBUILD file for alpine 3.18.4:

# secfixes:
#   2.361.2-r0:
#     - CVE-2022-2048
#     - CVE-2022-22970
#     - CVE-2022-22971
#   2.346.2-r0:
#     - CVE-2022-34174
#     - CVE-2022-34173
#     - CVE-2022-34172
#     - CVE-2022-34171
#     - CVE-2022-34170
#   2.332.1-r0:
#     - CVE-2022-20612       <---
#   2.319.3-r0:
#     - CVE-2022-0538
#   2.319.2-r0:
#     - CVE-2022-20612       <---
#   2.287-r0:
#     - CVE-2021-21639
#     - CVE-2021-21640
#   2.275-r0:
#     - CVE-2021-21602
#     - CVE-2021-21603
#     - CVE-2021-21604
#     - CVE-2021-21605
#     - CVE-2021-21606
#     - CVE-2021-21607
#     - CVE-2021-21608
#     - CVE-2021-21609
#     - CVE-2021-21610
#     - CVE-2021-21611
#   2.245-r0:
#     - CVE-2020-2220
#     - CVE-2020-2221
#     - CVE-2020-2222
#     - CVE-2020-2223
#   2.228-r0:
#     - CVE-2020-2160
#     - CVE-2020-2161
#     - CVE-2020-2162
#     - CVE-2020-2163
(grype-db entries)
sqlite3 vulnerability.db 'SELECT *  FROM vulnerability where id == "CVE-2022-20612";' | grep 'alpine:3.18'
281614|CVE-2022-20612|jenkins|alpine:distro:alpine:3.18||< 2.319.2-r0|apk||[{"id":"CVE-2022-20612","namespace":"nvd:cpe"}]|["2.319.2-r0"]|fixed|
281615|CVE-2022-20612|jenkins|alpine:distro:alpine:3.18||< 2.332.1-r0|apk||[{"id":"CVE-2022-20612","namespace":"nvd:cpe"}]|["2.332.1-r0"]|fixed|

The CPE that Syft can surmise is cpe:2.3:a:jenkins:jenkins:<apkversion>:*:*:*:*:*:*:*, which is the easiest of cases, so we should be able to match up by CPE for vendor and product since the NVD record shows cpe:2.3:a:jenkins:jenkins:*:*:*:*:lts:*:*:* with a node configuration of <= 2.319.1 || <= 2.329 .

(NVD node configuration from vunnel output)
...
      "configurations": [
        {
          "nodes": [
            {
              "operator": "OR",
              "negate": false,
              "cpeMatch": [
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:a:jenkins:jenkins:*:*:*:*:lts:*:*:*",
                  "versionEndIncluding": "2.319.1",
                  "matchCriteriaId": "ADE588E8-C485-4BA1-BBF6-50DC4B8C86BC"
                },
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:a:jenkins:jenkins:*:*:*:*:-:*:*:*",
                  "versionEndIncluding": "2.329",
                  "matchCriteriaId": "08A2ED7E-D17B-4A19-BB96-CB2AD13039BF"
                }
              ]
            }
          ]
        },
        {
          "nodes": [
            {
              "operator": "OR",
              "negate": false,
              "cpeMatch": [
                {
                  "vulnerable": true,
                  "criteria": "cpe:2.3:a:oracle:communications_cloud_native_core_automated_test_suite:1.9.0:*:*:*:*:*:*:*",
                  "matchCriteriaId": "A4CA84D6-F312-4C29-A02B-050FCB7A902B"
                }
              ]
            }
          ]
        }
      ],
...

Given the multiple overlapping ranges from both data sources, I'll simplify it to this:

  • NVD claims that jenkins is vulnerable for <= 2.329
  • The oversimplified range interpretation that grype makes of secdb fixes data claims that jenkins is vulnerable for <= 2.332.1-r0

Today we are not considering the != 2.319.2-r0 part, but like some of the other examples above, the apk matcher could be modified to consider this: <= 2.332.1-r0, != 2.319.2-r0.

I could see an issue if there were alpine packagings for jenkins > 2.329 and < 2.332.1-r0 (e.g. a fictitious 2.330 or 2.331 build)... in which case grype would be potentially incorrectly claiming that these versions are vulnerable when they are not , according to NVD. From what I can tell there are no builds that fit this criteria (the only build is 2.319.3, which would have been matched by the NVD record of <= 2.329) and the updates jump from 2.319.3 to 2.332.1.

@wagoodman
Copy link
Contributor

wagoodman commented Oct 24, 2023

IIRC, when we discovered the unexpected matches from the additive approach, the findings were all FPs.... I get the motivation of defending against FNs at all costs, but it might actually be a phantom problem here

I think the next step for this issue is an update to existing alpine vulnerability-match-labels images. Specifically:

  1. correct any labels that already exist that might be wrong relative to what is correct (where correct is "is the artifact vulnerable or not")
  2. add new image the express the specific false positives from real examples that we're trying to capture under test.

This will help us get a more holistic picture of if this proposal is better or not.

@luhring
Copy link
Contributor Author

luhring commented Oct 24, 2023

can we accurately craft an CPE for all APKs in the alpine ecosystem for matching against NVD?

If the bar being set here is "all", my guess is you won't achieve this. It's also helpful to remember that not all packages have assigned CPEs in the first place.

We have a growing set of manually-crafted mappings for apk packages

These CPEs don't look specific to Alpine or to the APK ecosystem to me. Alpine, like other distros, is packaging some well known software, and that software itself has CPEs.

But, I do think tracking down these CPEs is the right direction for Grype, if and only if it's going to continue to use NVD data for distro package matching. Some of this will be necessarily manual, since there's not always a reliable pattern for how CPEs get assigned to software applications. But even so, it's still valuable toward the objective of more accurate matching.

My suspicion is relying on Alpine's (and Wolfi's) secdbs as a source of new CVE matches is a less accurate but cheaper alternative to getting the CPE identification in better shape.

All this being said — I can't imagine this issue being the fastest path toward more accurate matches in Grype. I appreciate the investigation and hypotheticals. This stuff is really interesting to think about. I think if the Grype team wants to keep the current approach, that's certainly reasonable, and it's a defensible choice. It goes against the guidance of the distros involved, but possibly with a higher accuracy yield in some scenarios, especially without investing more in correct CPE identification. But my unsolicited prioritization input would be to focus on other higher return efforts! 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
5 participants