Software-Transparenzplattform

Wenn du denkst, dass die SBOM-Erstellung ein gelöstes Problem ist, arbeitest du wahrscheinlich nicht in C/C++.

Ein guter SBOM-Generator sollte drei Dinge gut beherrschen: genau sein, reproduzierbar sein und das darstellen, was tatsächlich in der Binärdatei oder Firmware steckt, die du auslieferst. Für Ökosysteme mit ausgereiften Paketmanagern und maschinenlesbaren Metadaten zu Abhängigkeiten ist das deutlich einfacher. JavaScript hat package-lock.json, Python hat oft poetry.lock, Rust hat Cargo.lock und Go hat go.sum. Diese Dateien machen die SBOM-Erstellung nicht trivial, aber sie bieten in der Regel einen wesentlich klareren Ausgangspunkt als C/C++.

Für C/C++ haben wir keinen solchen Luxus. Und in der Embedded-Welt, in der C/C++ dominiert, ist die Lücke zwischen dem, was SBOM-Tools erzeugen, und dem, was tatsächlich in deiner Firmware steckt, groß genug, um mit einem Lastwagen hindurchzufahren.

Ich habe viel Zeit damit verbracht, SBOM-Tools für eingebettete C/C++-Projekte zu entwickeln, und ich möchte eine ehrliche Einschätzung darüber teilen, wo die Lage heute steht — was funktioniert, was nicht, und warum ein kombinierter Ansatz der einzige realistische Weg zu einer einigermaßen genauen SBOM ist.

Die Geschichte der verwalteten Abhängigkeiten: Besser, aber nicht das ganze Bild

Tools wie CMake, Conan, vcpkg und Meson haben der C/C++-Abhängigkeitsverwaltung etwas Struktur verliehen. Wenn Ihr Projekt Conan verwendet, können Sie eine conan.lock-Datei erhalten. Wenn Sie vcpkg im Manifest-Modus verwenden, haben Sie zumindest ein vcpkg.json-Manifest und Versionsbeschränkungen. CMake-FetchContent-Deklarationen dokumentieren ebenfalls, was zur Konfigurationszeit eingebunden wird.

Einige SBOM-Tools können diese Metadaten nutzen und einen brauchbaren Ausgangspunkt für zumindest einen Teil des Abhängigkeitsgraphen erzeugen. Für den Teil der C/C++-Welt, der moderne Abhängigkeitsverwaltung konsequent übernommen hat, ist die SBOM-Situation besser als früher, auch wenn sie immer noch unvollständig ist.

Dieser Teil ist klein, besonders im Embedded-Bereich. Die meisten eingebetteten C/C++-Projekte, denen ich begegne, werden nicht mit Conan oder vcpkg erstellt. Sie werden mit einfachen Makefiles erstellt — manchmal von Hand geschrieben, manchmal von einer IDE wie IAR Embedded Workbench oder STM32CubeIDE erzeugt. Die Verbreitung von CMake wächst im Embedded-Bereich, ist aber noch längst nicht universell. Und selbst Projekte, die CMake verwenden, haben oft eine Mischung aus FetchContent, Systembibliotheken, Git-Submodulen und mitgeliefertem Quellcode, die kein einzelnes Tool vollständig erfasst.

Der Ansatz mit dem `-l`-Flag: Nützlich, aber unzureichend

Eine gängige Technik zum Identifizieren von C/C++-Abhängigkeiten besteht darin, die Linker-Eingaben zu prüfen — insbesondere -l-Flags und Linker-Suchpfade. Wenn Ihr Build gegen -lssl -lcrypto -lz linkt, kann ein Tool möglicherweise OpenSSL und zlib ableiten und dies mit Metadaten des Paketmanagers anreichern, wenn diese Bibliotheken aus dem Betriebssystem oder einer bekannten Paketquelle stammen. Dies kann sowohl dynamische Bibliotheken (.so / .dylib) als auch statische Archive (.a) abdecken, wenn der Build sie ausdrücklich benennt.

Für Desktop- und Server-Builds kann man mit diesem Ansatz recht weit kommen. Die -l-Flags in Kombination mit Linker-Suchpfaden (-L) verraten oft, welche Bibliotheken eingebunden werden. Auf diese Weise verknüpfte statische .a-Archive sind ebenfalls sichtbarer als mitgelieferter Quellcode, der direkt ins Ziel kompiliert wird.

Aber selbst wenn dieser Ansatz eine Komponente erfolgreich identifiziert, gibt es ein tieferliegendes Problem: Er liefert oft einen Bibliotheksnamen und manchmal eine Version, aber nicht viel mehr. Zu den Mindestbestandteilen der NTIA gehören Lieferantenname, Komponentenname, Version, eindeutige Kennungen, Abhängigkeitsbeziehungen, Autor der SBOM-Daten und Zeitstempel. Ein -l-Flag kann Ihnen einen Bibliotheksnamen nennen. Eine .a-Datei kann Ihnen vielleicht nur einen Dateinamen wie libfoo.a liefern, mit wenig oder gar keiner maschinenlesbaren Herkunft darüber, wer sie gebaut hat, woher sie stammt oder welchen Upstream-Release sie repräsentiert. Wenn die Bibliothek nicht aus einer Paketquelle mit Metadaten stammt, müssen die übrigen NTIA-Felder in der Regel auf andere Weise rekonstruiert werden — und bei den meisten C/C++-Projekten gibt es keinen automatisierten „anderen Weg“.

Im Embedded-Bereich ist die Lage deutlich schlimmer. Embedded-Firmware-Builds verwenden oft überhaupt keine -l-Flags, die auf systeminstallierte Pakete verweisen. Stattdessen kompilieren sie das RTOS, das HAL, den Netzwerk-Stack, die Kryptobibliothek und Middleware aus dem Quellcode — oder sie linken gegen projektlokale .a-Dateien, die zuvor aus mitgeliefertem Code mit nur wenig angehängten Metadaten gebaut wurden. Das resultierende Binary ist häufig monolithisch. Es kann keine Laufzeitabhängigkeitsinformationen im ldd-Stil geben, die man prüfen könnte, keine DT_NEEDED-Einträge in ELF-Headern, und gestrippte Symbole verringern, was eine Binäranalyse wiederherstellen kann. Eine statische .a-Datei im lib/-Verzeichnis eines Projekts, die Monate zuvor aus einer unbekannten Upstream-Version gebaut wurde, ist für SBOM-Zwecke nahezu eine Blackbox — und eine Compliance-Lücke für jede Regulierung, die mehr als nur einen Komponentennamen verlangt.

Vendored Code: Die eigentliche Herausforderung

Hier wird es wirklich schwierig, und hier denke ich, unterscheidet sich das C/C++-SBOM-Problem am stärksten von Ökosystemen mit starken Paketmanager-Konventionen.

Vendor-Code ist in C/C++ überall. Entwickler kopieren Quelldateien — manchmal nur ein einzelnes .c- und .h-Paar, manchmal ganze Bibliotheksbäume — direkt in ihr Projekt. Bibliotheken wie nlohmann/json, mongoose, stb_image, miniz und lwIP werden routinemäßig auf diese Weise integriert. Ihre eigene Dokumentation sagt Ihnen oft genau das: „Kopieren Sie diese beiden Dateien in Ihr Projekt.“ Einmal kopiert, ist der Code kaum von eigenem Quellcode zu unterscheiden.

Fingerprinting ist eine der wichtigsten Techniken zur Erkennung von vendored Code, und für die einfachen Fälle funktioniert es gut. Wenn ein Entwickler eine unveränderte Kopie einer eigenständigen Bibliothek vendored hat, können Sie die Dateien hashen, mit einem Korpus bekannter Releases vergleichen und oft eine sichere Übereinstimmung erhalten. Für kleine, in sich geschlossene Bibliotheken kann das ziemlich zuverlässig sein.

Aber das Vendoring bringt Komplikationen mit sich, die Fingerprinting zu einem heuristischen statt zu einem deterministischen Verfahren machen.

Modifikationen sind häufig. Entwickler vendoren Code und ändern ihn dann — beheben Fehler, passen APIs an, entfernen ungenutzte Funktionalität. Sobald eine Datei geändert wurde, schlägt exaktes Hash-Matching fehl. Dann bewegen Sie sich im Bereich des unscharfen Matchings: Vergleich mit bekannten Versionen, Techniken wie MinHash oder Winnowing zur Code-Ähnlichkeit oder struktureller Vergleich auf AST-Ebene. Diese Ansätze können funktionieren, bringen aber Unsicherheit mit sich. Handelt es sich um eine modifizierte Kopie von FreeRTOS 10.4.3 oder um FreeRTOS 10.5.1 mit anderen Änderungen? Die Antwort ist für die CVE-Korrelation wichtig, und die Tools können es Ihnen oft nicht mit Sicherheit sagen.

Vendor-SDKs bringen zusätzliches Rauschen mit sich. Halbleiterhersteller wie ST, NXP, TI und Renesas liefern SDKs aus, die Open-Source-Komponenten — FreeRTOS, lwIP, mbedTLS, FatFS — zusammen mit proprietärem HAL-Code bündeln. Diese Pakete fügen oft herstellerspezifische Copyright-Header hinzu, ändern Verzeichnisstrukturen, benennen Dateien um und forken den Upstream-Code manchmal erheblich. STM32CubeF4 enthält eine Version von FreeRTOS, die den Anpassungsprozess von ST durchlaufen hat. Renesas FSP bündelt ein ThreadX-Derivat. Diese gegen Upstream-Releases zu fingerprinten ist ohne herstellerspezifische Erkennungslogik unzuverlässig.

Einbettungsmodelle und ML-basierte Code-Ähnlichkeit können helfen, und es gibt interessante akademische Arbeiten zur Verwendung gelernter Code-Repräsentationen für die Identifikation von Softwarekomponenten. Aber heute sind diese Ansätze für die routinemäßige SBOM-Erstellung in CI in großem Maßstab meist zu aufwendig im Betrieb. Sie können bei einmaligen Audits oder hochsicheren Untersuchungen eine Rolle spielen, sind aber noch kein einfacher Ersatz für einfachere Techniken.

Das Problem des geteilten Lieferantenordners

Es gibt eine praktische Komplikation, die ich in SBOM-Gesprächen nicht oft genug diskutiert sehe. Die meisten C/C++-Entwickler halten ihren fremd eingebundenen Code in separaten Ordnern — vendor/, 3rdparty/, external/, lib/ — was die Verwaltung erleichtert. Das ist gute Hygiene und hilft SBOM-Tools, die Grenze zwischen eigenem und Drittanbieter-Code zu erkennen.

In der Praxis jedoch, besonders in Embedded-Unternehmen, wird ein solcher Ordner mit eingebundenem Code oft über mehrere Projekte oder Build-Ziele hinweg gemeinsam genutzt. Ein vendor/-Verzeichnis könnte FreeRTOS, lwIP, mbedTLS, FatFS und ein Dutzend weiterer Bibliotheken enthalten. Projekt A verwendet FreeRTOS und lwIP. Projekt B verwendet FreeRTOS und mbedTLS. Projekt C verwendet sie alle.

Ein SBOM-Generator, der einfach den gesamten Vendor-Ordner inventarisiert, erzeugt ein SBOM, das alle eingebundenen Komponenten auflistet — aber dieses SBOM ist für jedes einzelne Build-Artefakt falsch. Es stellt über, was tatsächlich im Binary enthalten ist. Wenn Projekt A mbedTLS nicht verwendet, führt die Auflistung in der SBOM von Projekt A zu False Positives bei Schwachstellenscans und stellt die tatsächliche Angriffsfläche falsch dar.

Selbst wenn der gesamte Code in einem Ordner mit eingebundenen Abhängigkeiten kompiliert und gelinkt wird, entfernt die --gc-sections-Option des Linkers alle Abschnitte, die vom Einstiegspunkt aus nicht erreichbar sind. Sie könnten 30 gemeinsam genutzte Bibliotheken in Ihren Build kompilieren, aber wenn ihre Funktionen nie aufgerufen werden, tragen sie null Bytes zum finalen Binary bei. Sie alle als Komponenten in Ihrer SBOM aufzulisten, würde ungenaue, falsch positive Ergebnisse erzeugen.

In vielen Embedded-Projekten ist der zuverlässigste Weg, dies richtig zu machen, zu verstehen, was das Build-System für ein bestimmtes Ziel tatsächlich kompiliert und linkt. Damit kommen wir wieder zum Build-System als einer wichtigen Quelle der Wahrheit zurück, und warum Laufzeitanalyse beim Build in der Regel für Embedded C/C++ unerlässlich ist.

Die reale Welt ist chaotisch: Ein kombinierter Ansatz

Keine einzelne Technik löst das C/C++-SBOM-Problem. Nachdem ich die verschiedenen Ansätze durchgearbeitet habe — Manifest-Parsing, Inspektion von Linker-Flags, Datei-Fingerprinting, Binäranalyse, Instrumentierung des Build-Systems — bin ich zu der Überzeugung gelangt, dass ein kombinierter Ansatz der einzige Weg zu einem hinreichend genauen SBOM ist. Konkret müssen vier Signale zusammengeführt werden:

Was gebaut wird. Das Build-System — ob Make, CMake, Meson, IAR oder etwas anderes — weiß, welche Quelldateien kompiliert und welche Bibliotheken für ein bestimmtes Ziel gelinkt werden. Wenn Sie den Build-Prozess instrumentieren, erhalten Sie die Ground Truth darüber, was in das Binärprogramm einfließt. Das ist die Grundlage.

Was eingebunden wird. Verzeichnis-Fingerprinting, Datei-Hashing und die Extraktion von Versionszeichenfolgen können bekannte Open-Source-Komponenten in Vendor-Verzeichnissen identifizieren. Der Schlüssel liegt darin, dies mit dem abzugleichen, was das Build-System tatsächlich verarbeitet — nicht nur mit dem, was auf der Festplatte vorhanden ist. Eine Komponente in vendor/, die niemals in Ihr Ziel kompiliert wird, sollte nicht in Ihrem SBOM erscheinen.

Für welche Plattform oder welchen Mikrocontroller es gebaut wird. Die Zielplattform schränkt ein, welche Vendor-SDKs und HAL-Bibliotheken relevant sind. Wenn Sie für einen STM32F4 bauen, wissen Sie, dass STM32CubeF4-HAL-Komponenten wahrscheinlich vorhanden sind. Wenn Sie auf einen Renesas RA6M4 abzielen, betrachten Sie Renesas FSP. Plattformbewusstsein hilft Ihnen, den Suchraum einzugrenzen und herstellerspezifische Erkennungsheuristiken anzuwenden. Es hilft auch bei der CPE/PURL-Zuordnung, da die Benennung eingebetteter Komponenten stark vom Hersteller abhängt.

Statische Abhängigkeitsverwaltung. Das Verständnis dafür, wie statische Bibliotheken (.a, .lib) verknüpft werden, welche Objektdateien sie enthalten und woher sie stammen, vervollständigt das Bild. Map-Dateien (.map), Linker-Skripte und Archivinhalte liefern allesamt Hinweise. Bei IAR-Projekten listen .map-Dateien jede Objektdatei auf, die in das finale Image eingebunden wird. Bei GCC-basierten Builds zeigt ar -t auf statischen Archiven deren Inhalte.

Jedes dieser Signale allein ist unvollständig. Zusammen können sie Sie zu einem genaueren SBOM führen, was in der Regel das ist, was für Schwachstellenmanagement, Beschaffung und regulatorisches Reporting zählt.

Auf diesem Design basiert lynkctl, Interlynks kommerzieller SBOM-Generator für eingebettetes C/C++ — eine toolchain-bewusste Extraktion aus GNU Make, CMake und IAR, kombiniert mit einem kuratierten Index für Open-Source-Software im Embedded-Bereich für die eingebundene Schicht.

Entwicklerkontext ist immer noch wichtig

Die automatisierte Erkennung ist wichtig, aber bei C/C++-Projekten, besonders eingebetteten, ist der vom Entwickler bereitgestellte Kontext weiterhin sehr wichtig. Das Entwicklungsteam weiß oft, welche eingebundene Bibliothek übernommen wurde, woher sie stammt, welche Patches angewendet wurden und welche Komponenten zu welcher Build-Variante gehören. Dieser Kontext ist genau die Art von Information, die automatisierte Scanner nur schwer zuverlässig aus Quellbäumen, Archiven und entschlackten Binärdateien rekonstruieren können.

Das bedeutet nicht, dass manuelle oder vom Entwickler gepflegte Manifeste eine Wunderlösung sind. Sie können veralten, Abhängigkeiten übersehen oder von der Realität abweichen, wenn sie nicht eng mit dem Build-Prozess verknüpft sind. In der Praxis können sie jedoch eine nützliche Ergänzung zur automatisierten Analyse sein, insbesondere für Provenienz-, Lieferanten-, Lizenz- und Build-Varianten-Metadaten, die im Nachhinein nur schwer abzuleiten sind.

Strukturierte Komponenten-Metadaten sind die fehlende Ebene in SBOMs — und Interlynk hilft dabei, sie zu definieren. Mit der neuen SBOM-Generierungsfunktion von sbomasm ermöglichen wir Teams, Entwicklerkontext dort zu erfassen, wo er entsteht, und machen automatisierte Scans und Buildzeit-Analysen deutlich zuverlässiger.

Wie geht es von hier aus weiter?

Das C/C++-SBOM-Problem wird nicht durch ein einzelnes Tool oder eine einzelne Technik gelöst werden. Es erfordert einen mehrschichtigen Ansatz, der Build-System-Intelligenz, die Erkennung von vendored Code, plattformbewusste Heuristiken und von der Community gepflegte Korpora bekannter eingebetteter Bibliotheken und ihrer Fingerabdrücke kombiniert.

Die Embedded-C/C++-Community muss außerdem in eine bessere Abhängigkeits-Hygiene investieren — wo möglich Paketmanager einführen, explizite Manifeste für vendored Code pflegen und die SBOM-Erstellung als erstklassiges Build-Artefakt statt als Nebensache behandeln.

Für diejenigen unter uns, die in diesem Bereich Tools entwickeln, ist die Chance klar: Wer die Kluft zwischen der Unordnung realer C/C++-Projekte und den strukturierten, genauen SBOMs, die Vorschriften verlangen, zuverlässig überbrücken kann, wird eines der schwierigsten verbleibenden Probleme in der Sicherheit der Software-Lieferkette lösen.

Und das wird eine SBOM sein, der Sie vertrauen und die Sie verifizieren können.

Erfahren Sie mehr über den Ansatz von Interlynk für Embedded

Zitationen

CMake, „FetchContent“, offizielle Dokumentation: https://cmake.org/cmake/help/latest/module/FetchContent.html

NTIA, „Die Mindestanforderungen für eine Software Bill of Materials (SBOM)“, Juli 2021: https://www.ntia.gov/sites/default/files/publications/sbom_minimum_elements_report_0.pdf

 Europäische Kommission, „Cyber Resilience Act - Umsetzung“, abgerufen am 9. April 2026: https://digital-strategy.ec.europa.eu/en/factpages/cyber-resilience-act-implementation

 FDA, „Medical Device Software Guidance Navigator“, einschließlich „Cybersicherheit in Medizinprodukten: Überlegungen zum Qualitätsmanagementsystem und Inhalt von Vorab-Einreichungen“: https://www.fda.gov/medical-devices/regulatory-accelerator/medical-device-software-guidance-navigator

Das Weiße Haus, „Executive Order on Improving the Nation's Cybersecurity“ (Executive Order 14028), 12. Mai 2021: https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/

sbomasm, „Ihr SBOM-Assembler“ : https://github.com/interlynk-io/sbomasm

Vertraut von Sicherheits- und Compliance-Teams in 100+ regulierten Unternehmen

Sehen Sie sich Ihr richtig erstelltes SBOM an

Interlynk automatisiert SBOMs, verwaltet Open-Source-Risiken, überwacht Lieferanten und bereitet Sie auf die Post-Quanten-Ära vor – alles auf einer vertrauenswürdigen Plattform.

Vertraut von Sicherheits- und Compliance-Teams in 100+ regulierten Unternehmen

Interlynk automatisiert SBOMs, verwaltet Open-Source-Risiken, überwacht Lieferanten und bereitet Sie auf das Post-Quanten-Zeitalter vor – alles auf einer vertrauenswürdigen Plattform.

Sehen Sie Ihr SBOM richtig gemacht

Vertraut von Sicherheits- und Compliance-Teams in 100+ regulierten Unternehmen

Interlynk automatisiert SBOMs, verwaltet Open-Source-Risiken, überwacht Lieferanten und bereitet Sie auf das Post-Quanten-Zeitalter vor – alles auf einer vertrauenswürdigen Plattform.

Sehen Sie Ihr SBOM richtig gemacht

{{DKNiivMjg | unsafeRaw}}