Challenges in Building Accurate SBOMs for C and C++ Projects Highlighted by CodeScoring Analysis

C and C++ ecosystems lack centralized package manifests, making SBOM generation far more complex than in Python, Java, or JavaScript. Libraries may arrive through system package managers like apt or dnf, build tools such as Conan and vcpkg, or direct source inclusion, with no single record of all components. CodeScoring’s Johnny agent uses eBPF to observe linker commands during builds and cross-references results with dpkg, RPM, and pkg-config metadata. The analysis distinguishes build-time SBOMs, which capture static libraries and compilation commands, from runtime SBOMs that reflect dynamic dependencies at execution. When version data cannot be verified, components are explicitly marked unresolved rather than guessed. The approach also addresses header-only libraries and patched artifacts that defeat simple hash matching.

HabrTranslated from Russian

Read at source

In ecosystems with established package indexes such as Python, Java, or JavaScript, project composition analysis typically begins with a manifest that lists direct dependencies and allowed versions. Package managers resolve these requirements, fetch transitive dependencies, and record exact versions in a lock file. C and C++ projects rarely follow this model. A single library may be installed via a system package manager, built from source in a separate pipeline, or copied directly into the project directory, leaving no unified record of all components that end up in the final binary.

CodeScoring examined these difficulties while automating SBOM generation for large codebases, including LibreOffice, which contains over one hundred C/C++ libraries plus fonts, dictionaries, and a custom build system. Without a single source of truth, each component requires separate investigation from build commands back to project name, version, and origin. The company’s analysis shows that even when a library is found through linker arguments such as -lssl or explicit paths like /opt/libs/libfoo.a, the command line rarely reveals the original project, version, or applied patches.

Build-time and runtime inventories produce two distinct SBOMs. Build-time SBOMs record libraries linked during compilation, chosen targets, and observed commands. Runtime SBOMs reflect the dynamic libraries actually loaded in a given execution environment. Reconciling the two lists is necessary because a statically linked library disappears from the runtime view, while a dynamically loaded library may be replaced by a different compatible version at launch.

When metadata is absent, Johnny falls back to normalized function signatures, binary section analysis, and strings, yet compiler optimizations and strip operations limit precision to family or version range rather than exact version. The tool marks unverifiable entries with an unresolved suffix and supports manual correction via --lib-versions files using generic PURL identifiers. CMake, Yocto, and experimental SPDX generation features already produce partial SBOMs, but any library supplied as a raw artifact still requires separate provenance work.

The resulting SBOM records must include supplier, PURL or CPE identifier, and evidence of identity. CycloneDX supports confidence levels and completeness statements, allowing analysts to avoid fabricating versions when data is insufficient. This disciplined approach prevents blind spots that arise when one type of inventory is substituted for the other.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Supply Chain & Open Source

Passwordless Kubernetes Image Pulling with Artifact Keeper via ServiceAccount Tokens
Malicious Code Injected into LiteLLM Open Source AI Package via Supply Chain Attack
GhostAction Campaign Compromises 790 GitHub Repositories via Malicious Workflows