Bug 16439

Summary: sbom-cve-check: Static linkage blindspot / CVEs dropped when recipe has empty RDEPENDS
Product: [Build System, Metadata & Runtime] OE-Core Reporter: Robert Berger <pokylinux>
Component: oe-core otherAssignee: Joshua Watt <JPEWhacker>
Status: NEW --- QA Contact:
Severity: normal    
Priority: Medium+ CC: benjamin.robin, ccasciato, randy.macleod
Version: 6.1   
Target Milestone: 6.2 M2   
Hardware: All   
OS: Multiple   
Whiteboard:
OS type for building Yocto: --- Type of Regression: ---
Verified: Documentation change: Don't know

Description Robert Berger 2026-09-26 15:58:55 UTC
Short Summary:
When an application recipe compiles a native C binary via CMake and explicitly links against a static library provider (e.g., DEPENDS = "zlib"), but declares RDEPENDS:${PN} = "" (since no runtime shared objects are shipped), the sbom-cve-check class completely drops the dependency mapping. 

As a result, any downstream generated SBOM or VEX manifest fails to inherit or associate the unpatched or patched CVEs of the static dependency (like zlib) with the calling application recipe. The static dependency only shows up at the image level under its own package name, making automated verification of the compiled binary impossible without manual CVE_PRODUCT workarounds in the application recipe.

Steps to Reproduce:

1. simple app[1]

[1] https://gitlab.com/exempli-gratia/zlib-test

2. Recipe:

cat zlib-static-test_1.0.bb 
SUMMARY = "Vulnerable Static zlib Linkage Test Application"
DESCRIPTION = "Builds a C application via CMake from Git that explicitly links statically against libz.a for Trivy verification."
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${UNPACKDIR}/${BPN}-${PV}/LICENSE;md5=0835ade698e0bcf8506ecda2f7b4f302"

DEPENDS = "zlib pkgconfig-native"

# Remote GitLab source configuration
SRC_URI = "git://gitlab.com/exempli-gratia/zlib-test.git;protocol=https;branch=master"
SRCREV = "${AUTOREV}"

inherit cmake

# Explicitly instruct CMake to bypass the shared object and link libz.a
EXTRA_OECMAKE += "-DZLIB_LIBRARY=${STAGING_LIBDIR}/libz.a"

do_install() {
    install -d ${D}${bindir}
    install -m 0755 ${B}/zlib_test ${D}${bindir}/zlib-static-test
}

RDEPENDS:${PN} = ""

# CVE_PRODUCT = "zlib"
# CVE_VERSION = "${@d.getVar('PV:pn-zlib') or '1.3.2'}"
# CVE_STATUS[CVE-2023-6992] = "fixed-version: Fixed upstream or via backport in standard zlib 1.3.2"
# CVE_STATUS[CVE-2026-27820] = "fixed-version: Only affects experimental or unreleased 3.x branches"

3. Config fragment:

bitbake-config-build show-fragment core/yocto/sbom-cve-check
NOTE: Starting bitbake server...
/workdir/build/yocto-ampliphy-master-2026-08-18-01-pinned/bitbake-builds/yocto-ampliphy-pinned/layers/openembedded-core/meta/conf/fragments/yocto/sbom-cve-check.conf:

BB_CONF_FRAGMENT_SUMMARY = "This fragment enables sbom-cve-check with recommended default options"
BB_CONF_FRAGMENT_DESCRIPTION = "Enables sbom-cve-check and applies the following configurations: \
 - Adds the sbom-cve-check class to IMAGE_CLASSES. \
 - Configures CVE database recipes to fetch the latest git revision using AUTOREV. \
 - Ensures generated SBOM includes all CVE annotations. \
 - Configures the Linux kernel recipe to provide compiled sources, \
   allowing CVEs to be excluded if the source is not compiled. \
"

INHERIT += "create-spdx"

IMAGE_CLASSES:append = " sbom-cve-check"

SRCREV:pn-sbom-cve-check-update-nvd-native = "${AUTOREV}"
SRCREV:pn-sbom-cve-check-update-cvelist-native = "${AUTOREV}"
# Drop the tag= or else do_unpack fails
SRC_URI:pn-sbom-cve-check-update-cvelist-native = "git://github.com/CVEProject/cvelistV5.git;branch=main;protocol=https;destsuffix="
SRC_URI:pn-sbom-cve-check-update-nvd-native = "git://github.com/fkie-cad/nvd-json-data-feeds.git;branch=main;protocol=https;destsuffix="

SPDX_INCLUDE_VEX = "all"
SPDX_INCLUDE_COMPILED_SOURCES:pn-linux-yocto = "1"
# also for -dev kernels:
SPDX_INCLUDE_COMPILED_SOURCES:pn-linux-yocto-dev = "1"

# -->
# Forces the CVE check to wait until the image has been fully built and deployed
# Otherwise we have a race condition with this oe-core version here - hopefully fixed in the future upstream
do_sbom_cve_check[depends] += "${PN}:do_image_complete"
# <--

3. Build the image: bitbake core-image-minimal
4. Run sbom-cve-check and inspect the generated standalone JSON or flattened CSV output.

Actual Results:
- The zlib component is correctly flagged for its CVEs (e.g., CVE-2026-85091), but it is tracked independently as a standalone package entry.
- The calling recipe (zlib-static-test) shows up as completely clean with 0 vulnerabilities, even though the unpatched, vulnerable machine code of libz.a has been baked straight into its binary file.
- Querying the true SPDX 3.0.1 relationship graph using jq on core-image-minimal.rootfs.sbom-cve-check.spdx.json reveals that the DEPENDENCY_OF or BUILD_DEPENDENCY_OF linkage tree between the application package and zlib vanishes during runtime image package collapse.

Expected Results:
The sbom-cve-check framework should leverage the build-time dependency tracking information from the recipe tasks. If an application utilizes a recipes' build output (DEPENDS) but leaves RDEPENDS blank, the CVE analyzer engine should propagate the underlying security footprint down the graph or explicitly map the dependency relations inside the image.rootfs.json VEX statement arrays.

Suggested Fix / Enhancement Idea:
Modify the post-build aggregation tasks within the class to query task-level dependency metadata (do_populate_sysroot linkages), ensuring that statically compiled providers are not discarded from the manifest's security hierarchy just because they do not exist as separate deployment targets inside the final root file system tree.

Workaround:

CVE_PRODUCT = "zlib"
CVE_VERSION = "${@d.getVar('PV:pn-zlib') or '1.3.2'}"
CVE_STATUS[CVE-2023-6992] = "fixed-version: Fixed upstream or via backport in standard zlib 1.3.2"
CVE_STATUS[CVE-2026-27820] = "fixed-version: Only affects experimental or unreleased 3.x branches"

It looks like the cve scanner works on a per-recipe bases and although it reports issues with zlib it only reports them because some other recipes have zlib installed and it looks like it analyzes them due to the added RDEPENDS. But this does not work for (only) statically linked libraries.
Comment 1 Benjamin Robin 2026-10-01 14:18:37 UTC
I am not agreeing with the analysis of the issue. Maybe the SBOM is missing some links but sbom-cve-check is doing what I am expecting.

To test test I have added a fake library that is declared a pcre2 library.
By default the core-image-minimal does not contain such a library.

*** fake-lib ***

./fake-libpcre2.bb:
```
SUMMARY = "Fake libpcre2"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://fake-libpcre2-src/"
S = "${UNPACKDIR}/fake-libpcre2-src"

CVE_PRODUCT = "pcre2"
PV = "10.43"

# expecting CVE-2026-86145

inherit cmake
```


./fake-libpcre2/fake-libpcre2-src/CMakeLists.txt:
```
cmake_minimum_required(VERSION 3.18)
project(fake_libpcre2 VERSION 1.0 LANGUAGES C)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(SOURCE_FILES fake_libpcre2.c)
add_library(fake_libpcre2 STATIC ${SOURCE_FILES})

include(GNUInstallDirs)
install(TARGETS fake_libpcre2 RUNTIME)
```


./fake-libpcre2/fake-libpcre2-src/fake_libpcre2.c:
```
#include <stdio.h>

int foo(void)
{
	printf("Hello\n");
	return 123;
}
```

*** test-app ***

./test-app.bb:
```
SUMMARY = "Test Application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

DEPENDS = "fake-libpcre2"

SRC_URI = "file://test-app-src/"
S = "${UNPACKDIR}/test-app-src"

RDEPENDS:${PN} = ""

inherit cmake
```


./test-app/test-app-src/CMakeLists.txt:
```
cmake_minimum_required(VERSION 3.18)
project(test_app VERSION 1.0 LANGUAGES C)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(SOURCE_FILES test_app.c)

add_executable(test_app ${SOURCE_FILES})
target_link_libraries(test_app PUBLIC fake_libpcre2)

include(GNUInstallDirs)
install(TARGETS test_app RUNTIME)
```


./test-app/test-app-src/test_app.c:
```
#include <stdio.h>

int foo(void);

int main(void)
{
	printf("=> %d\n", foo());
	return 0;
}

```

******* The result:

```
    {
      "name": "fake-libpcre2",
      "layer": "core",
      "version": "10.43",
      "products": [
        {
          "product": "pcre2",
          "cvesInRecord": "Yes"
        }
      ],
      "issue": [
        { ... },
        {
          "id": "CVE-2026-89160",
          "status": "Unpatched",
          "link": "https://nvd.nist.gov/vuln/detail/CVE-2026-89160",
          "summary": "PCRE2 before 10.48 has a pcre2_match out-of-bounds read during the PCRE2_MATCH_INVALID_UTF matching of an invalid UTF subject.",
          "scorev2": "0.0",
          "scorev3": "6.5",
          "scorev4": "0.0",
          "modified": "2026-09-16T19:15:29.000",
          "vector": "NETWORK",
          "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L",
          "detail": "version-in-range",
          "description": "Needs backporting (fixed from 10.48)"
        },
        { ... },
      ],
      "cpes": [
        "cpe:2.3:*:*:pcre2:10.43:*:*:*:*:*:*:*"
      ]
    },
```

The CVE is always attached to the component (here pcre2), not the application that contains the component (test-app).
Comment 2 Robert Berger 2026-10-01 16:46:48 UTC
Hmm interesting. Let me see if I can reproduce this. So you say that a library, which is only linked statically is recognized by the tooling even if we don't have RDEPENDS in the recipe.
Comment 3 Robert Berger 2026-10-01 17:49:21 UTC
Yes you are right. 

If you link a C library statically it's recognized: 
WARNING: core-image-minimal-1.0-r0 do_sbom_cve_check: zlib-fake-1.2.11: Found unpatched CVEs: CVE-2018-25032, CVE-2022-37434, CVE-2023-45853, CVE-2023-6992, CVE-2026-27171, CVE-2026-27820, CVE-2026-76844

So the issue seems to be only with "internal libraries like with go, rust, node, python,..." which are pulled in by one recipe.
Comment 4 Robert Berger 2026-10-02 08:24:57 UTC
Just for completeness I want to add that also header only libraries with vulnerabilities are detected by our tooling:

WARNING: core-image-minimal-1.0-r0 do_sbom_cve_check: nlohmann-json-fake-2.0.0: Found unpatched CVEs: CVE-2020-10663, CVE-2020-7712, CVE-2027-99999

The thing to keep in mind is, that it's not the app which uses the library, which is marked as vulnerable, but only the library, since it's per recipe.